Merge "Process input events immediately when received."
diff --git a/Android.mk b/Android.mk
index 5acfb86..79f6220 100644
--- a/Android.mk
+++ b/Android.mk
@@ -67,7 +67,6 @@
core/java/android/accounts/IAccountAuthenticatorResponse.aidl \
core/java/android/app/IActivityController.aidl \
core/java/android/app/IActivityPendingResult.aidl \
- core/java/android/app/IActivityWatcher.aidl \
core/java/android/app/IAlarmManager.aidl \
core/java/android/app/IBackupAgent.aidl \
core/java/android/app/IInstrumentationWatcher.aidl \
@@ -110,6 +109,7 @@
core/java/android/content/pm/IPackageMoveObserver.aidl \
core/java/android/content/pm/IPackageStatsObserver.aidl \
core/java/android/database/IContentObserver.aidl \
+ core/java/android/hardware/ISerialManager.aidl \
core/java/android/hardware/usb/IUsbManager.aidl \
core/java/android/net/IConnectivityManager.aidl \
core/java/android/net/INetworkManagementEventObserver.aidl \
diff --git a/api/16.txt b/api/16.txt
index 8e07844..be544de 100644
--- a/api/16.txt
+++ b/api/16.txt
@@ -15052,7 +15052,7 @@
method public static final deprecated boolean supportsProcesses();
field public static final int BLUETOOTH_GID = 2000; // 0x7d0
field public static final int FIRST_APPLICATION_UID = 10000; // 0x2710
- field public static final int LAST_APPLICATION_UID = 99999; // 0x1869f
+ field public static final int LAST_APPLICATION_UID = 19999; // 0x1869f
field public static final int PHONE_UID = 1001; // 0x3e9
field public static final int SIGNAL_KILL = 9; // 0x9
field public static final int SIGNAL_QUIT = 3; // 0x3
diff --git a/api/current.txt b/api/current.txt
index 574af6b..9a1d394b 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -562,6 +562,7 @@
field public static final int isRepeatable = 16843336; // 0x1010248
field public static final int isScrollContainer = 16843342; // 0x101024e
field public static final int isSticky = 16843335; // 0x1010247
+ field public static final int isolatedProcess = 16843687; // 0x10103a7
field public static final int itemBackground = 16843056; // 0x1010130
field public static final int itemIconDisabledAlpha = 16843057; // 0x1010131
field public static final int itemPadding = 16843565; // 0x101032d
@@ -6469,6 +6470,7 @@
method public int describeContents();
method public void dump(android.util.Printer, java.lang.String);
field public static final android.os.Parcelable.Creator CREATOR;
+ field public static final int FLAG_ISOLATED_PROCESS = 2; // 0x2
field public static final int FLAG_STOP_WITH_TASK = 1; // 0x1
field public int flags;
field public java.lang.String permission;
@@ -15178,7 +15180,7 @@
method public static final deprecated boolean supportsProcesses();
field public static final int BLUETOOTH_GID = 2000; // 0x7d0
field public static final int FIRST_APPLICATION_UID = 10000; // 0x2710
- field public static final int LAST_APPLICATION_UID = 99999; // 0x1869f
+ field public static final int LAST_APPLICATION_UID = 19999; // 0x4e1f
field public static final int PHONE_UID = 1001; // 0x3e9
field public static final int SIGNAL_KILL = 9; // 0x9
field public static final int SIGNAL_QUIT = 3; // 0x3
@@ -21598,6 +21600,26 @@
method public void println(java.lang.String);
}
+ public class LongSparseArray implements java.lang.Cloneable {
+ ctor public LongSparseArray();
+ ctor public LongSparseArray(int);
+ method public void append(long, E);
+ method public void clear();
+ method public android.util.LongSparseArray<E> clone();
+ method public void delete(long);
+ method public E get(long);
+ method public E get(long, E);
+ method public int indexOfKey(long);
+ method public int indexOfValue(E);
+ method public long keyAt(int);
+ method public void put(long, E);
+ method public void remove(long);
+ method public void removeAt(int);
+ method public void setValueAt(int, E);
+ method public int size();
+ method public E valueAt(int);
+ }
+
public class LruCache {
ctor public LruCache(int);
method protected V create(K);
@@ -24890,6 +24912,7 @@
method public void showSoftInputFromInputMethod(android.os.IBinder, int);
method public void showStatusIcon(android.os.IBinder, java.lang.String, int);
method public boolean switchToLastInputMethod(android.os.IBinder);
+ method public boolean switchToNextInputMethod(android.os.IBinder, boolean);
method public void toggleSoftInput(int, int);
method public void toggleSoftInputFromWindow(android.os.IBinder, int, int);
method public void updateCursor(android.view.View, int, int, int, int);
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 3d36ebf..901f7c7 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -215,6 +215,22 @@
list[i] = Long.valueOf(strings[i]);
}
intent.putExtra(key, list);
+ hasIntentInfo = true;
+ } else if (opt.equals("--ef")) {
+ String key = nextArgRequired();
+ String value = nextArgRequired();
+ intent.putExtra(key, Float.valueOf(value));
+ hasIntentInfo = true;
+ } else if (opt.equals("--efa")) {
+ String key = nextArgRequired();
+ String value = nextArgRequired();
+ String[] strings = value.split(",");
+ float[] list = new float[strings.length];
+ for (int i = 0; i < strings.length; i++) {
+ list[i] = Float.valueOf(strings[i]);
+ }
+ intent.putExtra(key, list);
+ hasIntentInfo = true;
} else if (opt.equals("--ez")) {
String key = nextArgRequired();
String value = nextArgRequired();
@@ -1342,9 +1358,11 @@
" [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]\n" +
" [--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]\n" +
" [--el <EXTRA_KEY> <EXTRA_LONG_VALUE> ...]\n" +
+ " [--ef <EXTRA_KEY> <EXTRA_FLOAT_VALUE> ...]\n" +
" [--eu <EXTRA_KEY> <EXTRA_URI_VALUE> ...]\n" +
" [--eia <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]]\n" +
" [--ela <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]\n" +
+ " [--efa <EXTRA_KEY> <EXTRA_FLOAT_VALUE>[,<EXTRA_FLOAT_VALUE...]]\n" +
" [-n <COMPONENT>] [-f <FLAGS>]\n" +
" [--grant-read-uri-permission] [--grant-write-uri-permission]\n" +
" [--debug-log-resolution] [--exclude-stopped-packages]\n" +
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index 4ed2489..cfc2d16 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -90,6 +90,7 @@
struct svcinfo *next;
void *ptr;
struct binder_death death;
+ int allow_isolated;
unsigned len;
uint16_t name[0];
};
@@ -125,13 +126,21 @@
};
-void *do_find_service(struct binder_state *bs, uint16_t *s, unsigned len)
+void *do_find_service(struct binder_state *bs, uint16_t *s, unsigned len, unsigned uid)
{
struct svcinfo *si;
si = find_svc(s, len);
// ALOGI("check_service('%s') ptr = %p\n", str8(s), si ? si->ptr : 0);
if (si && si->ptr) {
+ if (!si->allow_isolated) {
+ // If this service doesn't allow access from isolated processes,
+ // then check the uid to see if it is isolated.
+ unsigned appid = uid % AID_USER;
+ if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) {
+ return 0;
+ }
+ }
return si->ptr;
} else {
return 0;
@@ -140,10 +149,11 @@
int do_add_service(struct binder_state *bs,
uint16_t *s, unsigned len,
- void *ptr, unsigned uid)
+ void *ptr, unsigned uid, int allow_isolated)
{
struct svcinfo *si;
-// ALOGI("add_service('%s',%p) uid=%d\n", str8(s), ptr, uid);
+ //ALOGI("add_service('%s',%p,%s) uid=%d\n", str8(s), ptr,
+ // allow_isolated ? "allow_isolated" : "!allow_isolated", uid);
if (!ptr || (len == 0) || (len > 127))
return -1;
@@ -175,6 +185,7 @@
si->name[len] = '\0';
si->death.func = svcinfo_death;
si->death.ptr = si;
+ si->allow_isolated = allow_isolated;
si->next = svclist;
svclist = si;
}
@@ -194,6 +205,7 @@
unsigned len;
void *ptr;
uint32_t strict_policy;
+ int allow_isolated;
// ALOGI("target=%p code=%d pid=%d uid=%d\n",
// txn->target, txn->code, txn->sender_pid, txn->sender_euid);
@@ -217,7 +229,7 @@
case SVC_MGR_GET_SERVICE:
case SVC_MGR_CHECK_SERVICE:
s = bio_get_string16(msg, &len);
- ptr = do_find_service(bs, s, len);
+ ptr = do_find_service(bs, s, len, txn->sender_euid);
if (!ptr)
break;
bio_put_ref(reply, ptr);
@@ -226,7 +238,8 @@
case SVC_MGR_ADD_SERVICE:
s = bio_get_string16(msg, &len);
ptr = bio_get_ref(msg);
- if (do_add_service(bs, s, len, ptr, txn->sender_euid))
+ allow_isolated = bio_get_uint32(msg) ? 1 : 0;
+ if (do_add_service(bs, s, len, ptr, txn->sender_euid, allow_isolated))
return -1;
break;
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index e9642f7..11e94e8 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -35,7 +35,7 @@
record.cpp
LOCAL_SHARED_LIBRARIES := \
- libstagefright liblog libutils libbinder
+ libstagefright liblog libutils libbinder libstagefright_foundation
LOCAL_C_INCLUDES:= \
$(JNI_H_INCLUDE) \
@@ -59,7 +59,7 @@
recordvideo.cpp
LOCAL_SHARED_LIBRARIES := \
- libstagefright liblog libutils libbinder
+ libstagefright liblog libutils libbinder libstagefright_foundation
LOCAL_C_INCLUDES:= \
$(JNI_H_INCLUDE) \
@@ -84,7 +84,7 @@
audioloop.cpp
LOCAL_SHARED_LIBRARIES := \
- libstagefright liblog libutils libbinder
+ libstagefright liblog libutils libbinder libstagefright_foundation
LOCAL_C_INCLUDES:= \
$(JNI_H_INCLUDE) \
diff --git a/cmds/stagefright/SineSource.cpp b/cmds/stagefright/SineSource.cpp
index 021f636..14b4306 100644
--- a/cmds/stagefright/SineSource.cpp
+++ b/cmds/stagefright/SineSource.cpp
@@ -3,7 +3,7 @@
#include <math.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
diff --git a/cmds/stagefright/audioloop.cpp b/cmds/stagefright/audioloop.cpp
index 858681f..a6362a4 100644
--- a/cmds/stagefright/audioloop.cpp
+++ b/cmds/stagefright/audioloop.cpp
@@ -2,10 +2,10 @@
#include <binder/ProcessState.h>
#include <media/mediarecorder.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/AMRWriter.h>
#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/AudioSource.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/OMXClient.h>
@@ -24,7 +24,7 @@
android::ProcessState::self()->startThreadPool();
OMXClient client;
- CHECK_EQ(client.connect(), OK);
+ CHECK_EQ(client.connect(), (status_t)OK);
#if 0
sp<MediaSource> source = new SineSource(kSampleRate, kNumChannels);
@@ -82,7 +82,7 @@
delete player;
player = NULL;
#elif 0
- CHECK_EQ(decoder->start(), OK);
+ CHECK_EQ(decoder->start(), (status_t)OK);
MediaBuffer *buffer;
while (decoder->read(&buffer) == OK) {
@@ -95,7 +95,7 @@
buffer = NULL;
}
- CHECK_EQ(decoder->stop(), OK);
+ CHECK_EQ(decoder->stop(), (status_t)OK);
#endif
#endif
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index 7703058..45c3f7b 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -17,11 +17,11 @@
#include "SineSource.h"
#include <binder/ProcessState.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/CameraSource.h>
#include <media/stagefright/FileSource.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MediaExtractor.h>
@@ -183,7 +183,7 @@
return 1;
}
OMXClient client;
- CHECK_EQ(client.connect(), OK);
+ CHECK_EQ(client.connect(), (status_t)OK);
status_t err = OK;
@@ -231,14 +231,14 @@
sp<MPEG4Writer> writer = new MPEG4Writer("/sdcard/output.mp4");
writer->addSource(encoder);
writer->setMaxFileDuration(kDurationUs);
- CHECK_EQ(OK, writer->start());
+ CHECK_EQ((status_t)OK, writer->start());
while (!writer->reachedEOS()) {
fprintf(stderr, ".");
usleep(100000);
}
err = writer->stop();
#else
- CHECK_EQ(OK, encoder->start());
+ CHECK_EQ((status_t)OK, encoder->start());
MediaBuffer *buffer;
while (encoder->read(&buffer) == OK) {
@@ -272,7 +272,7 @@
for (int i = 0; i < 100; ++i) {
MediaBuffer *buffer;
status_t err = source->read(&buffer);
- CHECK_EQ(err, OK);
+ CHECK_EQ(err, (status_t)OK);
printf("got a frame, data=%p, size=%d\n",
buffer->data(), buffer->range_length());
@@ -299,7 +299,7 @@
android::ProcessState::self()->startThreadPool();
OMXClient client;
- CHECK_EQ(client.connect(), OK);
+ CHECK_EQ(client.connect(), (status_t)OK);
const int32_t kSampleRate = 22050;
const int32_t kNumChannels = 2;
diff --git a/cmds/stagefright/recordvideo.cpp b/cmds/stagefright/recordvideo.cpp
index c402286..3bd1fe2 100644
--- a/cmds/stagefright/recordvideo.cpp
+++ b/cmds/stagefright/recordvideo.cpp
@@ -17,9 +17,9 @@
#include "SineSource.h"
#include <binder/ProcessState.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MPEG4Writer.h>
@@ -243,7 +243,7 @@
}
OMXClient client;
- CHECK_EQ(client.connect(), OK);
+ CHECK_EQ(client.connect(), (status_t)OK);
status_t err = OK;
sp<MediaSource> source =
@@ -283,7 +283,7 @@
sp<MPEG4Writer> writer = new MPEG4Writer(fileName);
writer->addSource(encoder);
int64_t start = systemTime();
- CHECK_EQ(OK, writer->start());
+ CHECK_EQ((status_t)OK, writer->start());
while (!writer->reachedEOS()) {
}
err = writer->stop();
diff --git a/cmds/surfaceflinger/main_surfaceflinger.cpp b/cmds/surfaceflinger/main_surfaceflinger.cpp
index 78b1007..6dbcf5c 100644
--- a/cmds/surfaceflinger/main_surfaceflinger.cpp
+++ b/cmds/surfaceflinger/main_surfaceflinger.cpp
@@ -20,6 +20,6 @@
using namespace android;
int main(int argc, char** argv) {
- SurfaceFlinger::publishAndJoinThreadPool();
+ SurfaceFlinger::publishAndJoinThreadPool(true);
return 0;
}
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index d80902d..5a36466 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -554,15 +554,6 @@
return true;
}
- case FINISH_OTHER_INSTANCES_TRANSACTION: {
- data.enforceInterface(IActivityManager.descriptor);
- IBinder token = data.readStrongBinder();
- ComponentName className = ComponentName.readFromParcel(data);
- finishOtherInstances(token, className);
- reply.writeNoException();
- return true;
- }
-
case REPORT_THUMBNAIL_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder token = data.readStrongBinder();
@@ -679,8 +670,9 @@
String resolvedType = data.readString();
b = data.readStrongBinder();
int fl = data.readInt();
+ int userId = data.readInt();
IServiceConnection conn = IServiceConnection.Stub.asInterface(b);
- int res = bindService(app, token, service, resolvedType, conn, fl);
+ int res = bindService(app, token, service, resolvedType, conn, fl, userId);
reply.writeNoException();
reply.writeInt(res);
return true;
@@ -1192,22 +1184,6 @@
return true;
}
- case REGISTER_ACTIVITY_WATCHER_TRANSACTION: {
- data.enforceInterface(IActivityManager.descriptor);
- IActivityWatcher watcher = IActivityWatcher.Stub.asInterface(
- data.readStrongBinder());
- registerActivityWatcher(watcher);
- return true;
- }
-
- case UNREGISTER_ACTIVITY_WATCHER_TRANSACTION: {
- data.enforceInterface(IActivityManager.descriptor);
- IActivityWatcher watcher = IActivityWatcher.Stub.asInterface(
- data.readStrongBinder());
- unregisterActivityWatcher(watcher);
- return true;
- }
-
case START_ACTIVITY_IN_PACKAGE_TRANSACTION:
{
data.enforceInterface(IActivityManager.descriptor);
@@ -2164,18 +2140,6 @@
reply.recycle();
return res;
}
- public void finishOtherInstances(IBinder token, ComponentName className) throws RemoteException
- {
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- data.writeInterfaceToken(IActivityManager.descriptor);
- data.writeStrongBinder(token);
- ComponentName.writeToParcel(className, data);
- mRemote.transact(FINISH_OTHER_INSTANCES_TRANSACTION, data, reply, 0);
- reply.readException();
- data.recycle();
- reply.recycle();
- }
public void reportThumbnail(IBinder token,
Bitmap thumbnail, CharSequence description) throws RemoteException
{
@@ -2325,7 +2289,7 @@
}
public int bindService(IApplicationThread caller, IBinder token,
Intent service, String resolvedType, IServiceConnection connection,
- int flags) throws RemoteException {
+ int flags, int userId) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
@@ -2335,6 +2299,7 @@
data.writeString(resolvedType);
data.writeStrongBinder(connection.asBinder());
data.writeInt(flags);
+ data.writeInt(userId);
mRemote.transact(BIND_SERVICE_TRANSACTION, data, reply, 0);
reply.readException();
int res = reply.readInt();
@@ -3024,30 +2989,6 @@
data.recycle();
}
- public void registerActivityWatcher(IActivityWatcher watcher)
- throws RemoteException {
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- data.writeInterfaceToken(IActivityManager.descriptor);
- data.writeStrongBinder(watcher != null ? watcher.asBinder() : null);
- mRemote.transact(REGISTER_ACTIVITY_WATCHER_TRANSACTION, data, reply, 0);
- reply.readException();
- data.recycle();
- reply.recycle();
- }
-
- public void unregisterActivityWatcher(IActivityWatcher watcher)
- throws RemoteException {
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- data.writeInterfaceToken(IActivityManager.descriptor);
- data.writeStrongBinder(watcher != null ? watcher.asBinder() : null);
- mRemote.transact(UNREGISTER_ACTIVITY_WATCHER_TRANSACTION, data, reply, 0);
- reply.readException();
- data.recycle();
- reply.recycle();
- }
-
public int startActivityInPackage(int uid,
Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, boolean onlyIfNeeded)
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index e4cfc99..bf632a9 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -134,7 +134,7 @@
private static final boolean DEBUG_RESULTS = false;
private static final boolean DEBUG_BACKUP = true;
private static final boolean DEBUG_CONFIGURATION = false;
- private static final boolean DEBUG_SERVICE = true;
+ private static final boolean DEBUG_SERVICE = false;
private static final long MIN_TIME_BETWEEN_GCS = 5*1000;
private static final Pattern PATTERN_SEMICOLON = Pattern.compile(";");
private static final int SQLITE_MEM_RELEASED_EVENT_LOG_TAG = 75003;
@@ -3764,13 +3764,17 @@
}
private void setupGraphicsSupport(LoadedApk info) {
+ if (Process.isIsolated()) {
+ // Isolated processes aren't going to do UI.
+ return;
+ }
try {
int uid = Process.myUid();
String[] packages = getPackageManager().getPackagesForUid(uid);
// If there are several packages in this application we won't
// initialize the graphics disk caches
- if (packages.length == 1) {
+ if (packages != null && packages.length == 1) {
ContextImpl appContext = new ContextImpl();
appContext.init(info, null, this);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index db5113e..ebf692a 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -42,7 +42,9 @@
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
+import android.hardware.ISerialManager;
import android.hardware.SensorManager;
+import android.hardware.SerialManager;
import android.hardware.usb.IUsbManager;
import android.hardware.usb.UsbManager;
import android.location.CountryDetector;
@@ -428,6 +430,12 @@
return new UsbManager(ctx, IUsbManager.Stub.asInterface(b));
}});
+ registerService(SERIAL_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(SERIAL_SERVICE);
+ return new SerialManager(ctx, ISerialManager.Stub.asInterface(b));
+ }});
+
registerService(VIBRATOR_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
return new Vibrator();
@@ -1117,6 +1125,12 @@
@Override
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
+ return bindService(service, conn, flags, UserId.getUserId(Process.myUid()));
+ }
+
+ /** @hide */
+ @Override
+ public boolean bindService(Intent service, ServiceConnection conn, int flags, int userId) {
IServiceConnection sd;
if (mPackageInfo != null) {
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
@@ -1135,7 +1149,7 @@
int res = ActivityManagerNative.getDefault().bindService(
mMainThread.getApplicationThread(), getActivityToken(),
service, service.resolveTypeIfNeeded(getContentResolver()),
- sd, flags);
+ sd, flags, userId);
if (res < 0) {
throw new SecurityException(
"Not allowed to bind to service " + service);
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 39817ac..7deb615 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -145,7 +145,6 @@
public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) throws RemoteException;
public void moveTaskBackwards(int task) throws RemoteException;
public int getTaskForActivity(IBinder token, boolean onlyRoot) throws RemoteException;
- public void finishOtherInstances(IBinder token, ComponentName className) throws RemoteException;
/* oneway */
public void reportThumbnail(IBinder token,
Bitmap thumbnail, CharSequence description) throws RemoteException;
@@ -167,7 +166,7 @@
int id, Notification notification, boolean keepNotification) throws RemoteException;
public int bindService(IApplicationThread caller, IBinder token,
Intent service, String resolvedType,
- IServiceConnection connection, int flags) throws RemoteException;
+ IServiceConnection connection, int flags, int userId) throws RemoteException;
public boolean unbindService(IServiceConnection connection) throws RemoteException;
public void publishService(IBinder token,
Intent intent, IBinder service) throws RemoteException;
@@ -295,11 +294,6 @@
public void stopAppSwitches() throws RemoteException;
public void resumeAppSwitches() throws RemoteException;
- public void registerActivityWatcher(IActivityWatcher watcher)
- throws RemoteException;
- public void unregisterActivityWatcher(IActivityWatcher watcher)
- throws RemoteException;
-
public int startActivityInPackage(int uid,
Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, boolean onlyIfNeeded)
@@ -505,7 +499,7 @@
int BIND_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+35;
int UNBIND_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+36;
int PUBLISH_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+37;
- int FINISH_OTHER_INSTANCES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+38;
+
int GOING_TO_SLEEP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+39;
int WAKING_UP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+40;
int SET_DEBUG_APP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+41;
@@ -559,8 +553,8 @@
int START_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+89;
int BACKUP_AGENT_CREATED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+90;
int UNBIND_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+91;
- int REGISTER_ACTIVITY_WATCHER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+92;
- int UNREGISTER_ACTIVITY_WATCHER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+93;
+
+
int START_ACTIVITY_IN_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+94;
int KILL_APPLICATION_WITH_UID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+95;
int CLOSE_SYSTEM_DIALOGS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+96;
diff --git a/core/java/android/app/IActivityWatcher.aidl b/core/java/android/app/IActivityWatcher.aidl
deleted file mode 100644
index 6737545..0000000
--- a/core/java/android/app/IActivityWatcher.aidl
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
-**
-** Copyright 2009, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-package android.app;
-
-/**
- * Callback interface to watch the user's traversal through activities.
- * {@hide}
- */
-oneway interface IActivityWatcher {
- void activityResuming(int activityId);
- void closingSystemDialogs(String reason);
-}
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index fcbcd81..d9bbb4a 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -119,7 +119,7 @@
final int myUid = Process.myUid();
mResDir = aInfo.uid == myUid ? aInfo.sourceDir
: aInfo.publicSourceDir;
- if (!UserId.isSameUser(aInfo.uid, myUid)) {
+ if (!UserId.isSameUser(aInfo.uid, myUid) && !Process.isIsolated()) {
aInfo.dataDir = PackageManager.getDataDirForUser(UserId.getUserId(myUid),
mPackageName);
}
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index c1e28b0..c057d66 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -30,6 +30,7 @@
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
+import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -433,7 +434,12 @@
*/
public WallpaperInfo getWallpaperInfo() {
try {
- return sGlobals.mService.getWallpaperInfo();
+ if (sGlobals.mService == null) {
+ Log.w(TAG, "WallpaperService not running");
+ return null;
+ } else {
+ return sGlobals.mService.getWallpaperInfo();
+ }
} catch (RemoteException e) {
return null;
}
@@ -451,6 +457,10 @@
* wallpaper.
*/
public void setResource(int resid) throws IOException {
+ if (sGlobals.mService == null) {
+ Log.w(TAG, "WallpaperService not running");
+ return;
+ }
try {
Resources resources = mContext.getResources();
/* Set the wallpaper to the default values */
@@ -483,6 +493,10 @@
* wallpaper.
*/
public void setBitmap(Bitmap bitmap) throws IOException {
+ if (sGlobals.mService == null) {
+ Log.w(TAG, "WallpaperService not running");
+ return;
+ }
try {
ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null);
if (fd == null) {
@@ -515,6 +529,10 @@
* wallpaper.
*/
public void setStream(InputStream data) throws IOException {
+ if (sGlobals.mService == null) {
+ Log.w(TAG, "WallpaperService not running");
+ return;
+ }
try {
ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null);
if (fd == null) {
@@ -558,6 +576,10 @@
* mandatory.
*/
public int getDesiredMinimumWidth() {
+ if (sGlobals.mService == null) {
+ Log.w(TAG, "WallpaperService not running");
+ return 0;
+ }
try {
return sGlobals.mService.getWidthHint();
} catch (RemoteException e) {
@@ -581,6 +603,10 @@
* mandatory.
*/
public int getDesiredMinimumHeight() {
+ if (sGlobals.mService == null) {
+ Log.w(TAG, "WallpaperService not running");
+ return 0;
+ }
try {
return sGlobals.mService.getHeightHint();
} catch (RemoteException e) {
@@ -599,7 +625,11 @@
*/
public void suggestDesiredDimensions(int minimumWidth, int minimumHeight) {
try {
- sGlobals.mService.setDimensionHints(minimumWidth, minimumHeight);
+ if (sGlobals.mService == null) {
+ Log.w(TAG, "WallpaperService not running");
+ } else {
+ sGlobals.mService.setDimensionHints(minimumWidth, minimumHeight);
+ }
} catch (RemoteException e) {
// Ignore
}
diff --git a/core/java/android/app/backup/WallpaperBackupHelper.java b/core/java/android/app/backup/WallpaperBackupHelper.java
index 170171e..a74a268 100644
--- a/core/java/android/app/backup/WallpaperBackupHelper.java
+++ b/core/java/android/app/backup/WallpaperBackupHelper.java
@@ -38,15 +38,23 @@
private static final boolean DEBUG = false;
// This path must match what the WallpaperManagerService uses
- private static final String WALLPAPER_IMAGE = "/data/data/com.android.settings/files/wallpaper";
+ // TODO: Will need to change if backing up non-primary user's wallpaper
+ public static final String WALLPAPER_IMAGE = "/data/system/users/0/wallpaper";
+ public static final String WALLPAPER_INFO = "/data/system/users/0/wallpaper_info.xml";
+ // Use old keys to keep legacy data compatibility and avoid writing two wallpapers
+ public static final String WALLPAPER_IMAGE_KEY =
+ "/data/data/com.android.settings/files/wallpaper";
+ public static final String WALLPAPER_INFO_KEY = "/data/system/wallpaper_info.xml";
// Stage file - should be adjacent to the WALLPAPER_IMAGE location. The wallpapers
// will be saved to this file from the restore stream, then renamed to the proper
// location if it's deemed suitable.
- private static final String STAGE_FILE = "/data/data/com.android.settings/files/wallpaper-tmp";
+ // TODO: Will need to change if backing up non-primary user's wallpaper
+ private static final String STAGE_FILE = "/data/system/users/0/wallpaper-tmp";
Context mContext;
String[] mFiles;
+ String[] mKeys;
double mDesiredMinWidth;
double mDesiredMinHeight;
@@ -57,11 +65,12 @@
* @param context
* @param files
*/
- public WallpaperBackupHelper(Context context, String... files) {
+ public WallpaperBackupHelper(Context context, String[] files, String[] keys) {
super(context);
mContext = context;
mFiles = files;
+ mKeys = keys;
WallpaperManager wpm;
wpm = (WallpaperManager) context.getSystemService(Context.WALLPAPER_SERVICE);
@@ -89,7 +98,7 @@
*/
public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
ParcelFileDescriptor newState) {
- performBackup_checked(oldState, data, newState, mFiles, mFiles);
+ performBackup_checked(oldState, data, newState, mFiles, mKeys);
}
/**
@@ -99,8 +108,8 @@
*/
public void restoreEntity(BackupDataInputStream data) {
final String key = data.getKey();
- if (isKeyInList(key, mFiles)) {
- if (key.equals(WALLPAPER_IMAGE)) {
+ if (isKeyInList(key, mKeys)) {
+ if (key.equals(WALLPAPER_IMAGE_KEY)) {
// restore the file to the stage for inspection
File f = new File(STAGE_FILE);
if (writeFile(f, data)) {
@@ -135,9 +144,9 @@
f.delete();
}
}
- } else {
- // Some other normal file; just decode it to its destination
- File f = new File(key);
+ } else if (key.equals(WALLPAPER_INFO_KEY)) {
+ // XML file containing wallpaper info
+ File f = new File(WALLPAPER_INFO);
writeFile(f, data);
}
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index bfbd0ac..6d4cdae 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1307,6 +1307,15 @@
int flags);
/**
+ * Same as {@link #bindService(Intent, ServiceConnection, int)}, but with an explicit userId
+ * argument for use by system server and other multi-user aware code.
+ * @hide
+ */
+ public boolean bindService(Intent service, ServiceConnection conn, int flags, int userId) {
+ throw new RuntimeException("Not implemented. Must override in a subclass.");
+ }
+
+ /**
* Disconnect from an application service. You will no longer receive
* calls as the service is restarted, and the service is now allowed to
* stop at any time.
@@ -1789,6 +1798,17 @@
public static final String USB_SERVICE = "usb";
/**
+ * Use with {@link #getSystemService} to retrieve a {@link
+ * android.hardware.SerialManager} for access to serial ports.
+ *
+ * @see #getSystemService
+ * @see android.harware.SerialManager
+ *
+ * @hide
+ */
+ public static final String SERIAL_SERVICE = "serial";
+
+ /**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.
*
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 3928aaf..cd8d87f 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -370,6 +370,12 @@
return mBase.bindService(service, conn, flags);
}
+ /** @hide */
+ @Override
+ public boolean bindService(Intent service, ServiceConnection conn, int flags, int userId) {
+ return mBase.bindService(service, conn, flags, userId);
+ }
+
@Override
public void unbindService(ServiceConnection conn) {
mBase.unbindService(conn);
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index faee873..8029bd5 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2581,6 +2581,11 @@
false)) {
s.info.flags |= ServiceInfo.FLAG_STOP_WITH_TASK;
}
+ if (sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestService_isolatedProcess,
+ false)) {
+ s.info.flags |= ServiceInfo.FLAG_ISOLATED_PROCESS;
+ }
sa.recycle();
@@ -3375,7 +3380,8 @@
public static final ServiceInfo generateServiceInfo(Service s, int flags, int userId) {
if (s == null) return null;
- if (!copyNeeded(flags, s.owner, s.metaData) && userId == 0) {
+ if (!copyNeeded(flags, s.owner, s.metaData)
+ && userId == UserId.getUserId(s.info.applicationInfo.uid)) {
return s.info;
}
// Make shallow copies so we can store the metadata safely
diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java
index 612e345..7ee84ab 100644
--- a/core/java/android/content/pm/ServiceInfo.java
+++ b/core/java/android/content/pm/ServiceInfo.java
@@ -42,10 +42,17 @@
public static final int FLAG_STOP_WITH_TASK = 0x0001;
/**
+ * Bit in {@link #flags}: If set, the service will run in its own
+ * isolated process. Set from the
+ * {@link android.R.attr#isolatedProcess} attribute.
+ */
+ public static final int FLAG_ISOLATED_PROCESS = 0x0002;
+
+ /**
* Options that have been set in the service declaration in the
* manifest.
* These include:
- * {@link #FLAG_STOP_WITH_TASK}
+ * {@link #FLAG_STOP_WITH_TASK}, {@link #FLAG_ISOLATED_PROCESS}.
*/
public int flags;
diff --git a/core/java/android/hardware/ISerialManager.aidl b/core/java/android/hardware/ISerialManager.aidl
new file mode 100644
index 0000000..74d30f7
--- /dev/null
+++ b/core/java/android/hardware/ISerialManager.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2011 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.hardware;
+
+import android.os.ParcelFileDescriptor;
+
+/** @hide */
+interface ISerialManager
+{
+ /* Returns a list of all available serial ports */
+ String[] getSerialPorts();
+
+ /* Returns a file descriptor for the serial port. */
+ ParcelFileDescriptor openSerialPort(String name);
+}
diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java
index 784bcc5..51a17c1 100644
--- a/core/java/android/hardware/SensorEvent.java
+++ b/core/java/android/hardware/SensorEvent.java
@@ -294,7 +294,7 @@
* <li>X is defined as the vector product <b>Y.Z</b> (It is tangential to
* the ground at the device's current location and roughly points East).</li>
* <li>Y is tangential to the ground at the device's current location and
- * points towards the magnetic North Pole.</li>
+ * points towards magnetic north.</li>
* <li>Z points towards the sky and is perpendicular to the ground.</li>
* </ul>
*
diff --git a/core/java/android/hardware/SerialManager.java b/core/java/android/hardware/SerialManager.java
new file mode 100644
index 0000000..c5e1c2b
--- /dev/null
+++ b/core/java/android/hardware/SerialManager.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2011 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.hardware;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.HashMap;
+
+/**
+ * @hide
+ */
+public class SerialManager {
+ private static final String TAG = "SerialManager";
+
+ private final Context mContext;
+ private final ISerialManager mService;
+
+ /**
+ * {@hide}
+ */
+ public SerialManager(Context context, ISerialManager service) {
+ mContext = context;
+ mService = service;
+ }
+
+ /**
+ * Returns a string array containing the names of available serial ports
+ *
+ * @return names of available serial ports
+ */
+ public String[] getSerialPorts() {
+ try {
+ return mService.getSerialPorts();
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in getSerialPorts", e);
+ return null;
+ }
+ }
+
+ /**
+ * Opens and returns the {@link android.hardware.SerialPort} with the given name.
+ * The speed of the serial port must be one of:
+ * 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600,
+ * 19200, 38400, 57600, 115200, 230400, 460800, 500000, 576000, 921600, 1000000, 1152000,
+ * 1500000, 2000000, 2500000, 3000000, 3500000 or 4000000
+ *
+ * @param name of the serial port
+ * @param speed at which to open the serial port
+ * @return the serial port
+ */
+ public SerialPort openSerialPort(String name, int speed) throws IOException {
+ try {
+ ParcelFileDescriptor pfd = mService.openSerialPort(name);
+ if (pfd != null) {
+ SerialPort port = new SerialPort(name);
+ port.open(pfd, speed);
+ return port;
+ } else {
+ throw new IOException("Could not open serial port " + name);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "exception in UsbManager.openDevice", e);
+ }
+ return null;
+ }
+}
diff --git a/core/java/android/hardware/SerialPort.java b/core/java/android/hardware/SerialPort.java
new file mode 100644
index 0000000..5ef122b
--- /dev/null
+++ b/core/java/android/hardware/SerialPort.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2011 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.hardware;
+
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import java.nio.ByteBuffer;
+
+/**
+ * @hide
+ */
+public class SerialPort {
+
+ private static final String TAG = "SerialPort";
+
+ // used by the JNI code
+ private int mNativeContext;
+ private final String mName;
+ private ParcelFileDescriptor mFileDescriptor;
+
+ /**
+ * SerialPort should only be instantiated by SerialManager
+ * @hide
+ */
+ public SerialPort(String name) {
+ mName = name;
+ }
+
+ /**
+ * SerialPort should only be instantiated by SerialManager
+ * Speed must be one of 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600,
+ * 19200, 38400, 57600, 115200, 230400, 460800, 500000, 576000, 921600, 1000000, 1152000,
+ * 1500000, 2000000, 2500000, 3000000, 3500000, 4000000
+ *
+ * @hide
+ */
+ public void open(ParcelFileDescriptor pfd, int speed) throws IOException {
+ native_open(pfd.getFileDescriptor(), speed);
+ mFileDescriptor = pfd;
+ }
+
+ /**
+ * Closes the serial port
+ */
+ public void close() throws IOException {
+ if (mFileDescriptor != null) {
+ mFileDescriptor.close();
+ mFileDescriptor = null;
+ }
+ native_close();
+ }
+
+ /**
+ * Returns the name of the serial port
+ *
+ * @return the serial port's name
+ */
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * Reads data into the provided buffer
+ *
+ * @param buffer to read into
+ * @return number of bytes read
+ */
+ public int read(ByteBuffer buffer) throws IOException {
+ if (buffer.isDirect()) {
+ return native_read_direct(buffer, buffer.remaining());
+ } else if (buffer.hasArray()) {
+ return native_read_array(buffer.array(), buffer.remaining());
+ } else {
+ throw new IllegalArgumentException("buffer is not direct and has no array");
+ }
+ }
+
+ /**
+ * Writes data from provided buffer
+ *
+ * @param buffer to write
+ * @param length number of bytes to write
+ */
+ public void write(ByteBuffer buffer, int length) throws IOException {
+ if (buffer.isDirect()) {
+ native_write_direct(buffer, length);
+ } else if (buffer.hasArray()) {
+ native_write_array(buffer.array(), length);
+ } else {
+ throw new IllegalArgumentException("buffer is not direct and has no array");
+ }
+ }
+
+ /**
+ * Sends a stream of zero valued bits for 0.25 to 0.5 seconds
+ */
+ public void sendBreak() {
+ native_send_break();
+ }
+
+ private native void native_open(FileDescriptor pfd, int speed) throws IOException;
+ private native void native_close();
+ private native int native_read_array(byte[] buffer, int length) throws IOException;
+ private native int native_read_direct(ByteBuffer buffer, int length) throws IOException;
+ private native void native_write_array(byte[] buffer, int length) throws IOException;
+ private native void native_write_direct(ByteBuffer buffer, int length) throws IOException;
+ private native void native_send_break();
+}
diff --git a/core/java/android/net/EthernetDataTracker.java b/core/java/android/net/EthernetDataTracker.java
index 21ecc22..fb09ba5 100644
--- a/core/java/android/net/EthernetDataTracker.java
+++ b/core/java/android/net/EthernetDataTracker.java
@@ -49,6 +49,7 @@
private LinkCapabilities mLinkCapabilities;
private NetworkInfo mNetworkInfo;
private InterfaceObserver mInterfaceObserver;
+ private String mHwAddr;
/* For sending events to connectivity service handler */
private Handler mCsHandler;
@@ -74,15 +75,13 @@
if (mIface.equals(iface) && mLinkUp != up) {
Log.d(TAG, "Interface " + iface + " link " + (up ? "up" : "down"));
mLinkUp = up;
+ mTracker.mNetworkInfo.setIsAvailable(up);
// use DHCP
if (up) {
mTracker.reconnect();
} else {
- NetworkUtils.stopDhcp(mIface);
- mTracker.mNetworkInfo.setIsAvailable(false);
- mTracker.mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED,
- null, null);
+ mTracker.disconnect();
}
}
}
@@ -104,10 +103,6 @@
mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORKTYPE, "");
mLinkProperties = new LinkProperties();
mLinkCapabilities = new LinkCapabilities();
- mLinkUp = false;
-
- mNetworkInfo.setIsAvailable(false);
- setTeardownRequested(false);
}
private void interfaceAdded(String iface) {
@@ -116,7 +111,7 @@
Log.d(TAG, "Adding " + iface);
- synchronized(mIface) {
+ synchronized(this) {
if(!mIface.isEmpty())
return;
mIface = iface;
@@ -125,21 +120,15 @@
mNetworkInfo.setIsAvailable(true);
Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
msg.sendToTarget();
-
- runDhcp();
}
- private void interfaceRemoved(String iface) {
- if (!iface.equals(mIface))
- return;
-
- Log.d(TAG, "Removing " + iface);
+ public void disconnect() {
NetworkUtils.stopDhcp(mIface);
mLinkProperties.clear();
mNetworkInfo.setIsAvailable(false);
- mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
+ mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr);
Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
msg.sendToTarget();
@@ -147,6 +136,21 @@
msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
msg.sendToTarget();
+ IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+ INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
+ try {
+ service.clearInterfaceAddresses(mIface);
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to clear addresses or disable ipv6" + e);
+ }
+ }
+
+ private void interfaceRemoved(String iface) {
+ if (!iface.equals(mIface))
+ return;
+
+ Log.d(TAG, "Removing " + iface);
+ disconnect();
mIface = "";
}
@@ -161,7 +165,7 @@
mLinkProperties = dhcpInfoInternal.makeLinkProperties();
mLinkProperties.setInterfaceName(mIface);
- mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
+ mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, mHwAddr);
Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
msg.sendToTarget();
}
@@ -208,8 +212,15 @@
for (String iface : ifaces) {
if (iface.matches(sIfaceMatch)) {
mIface = iface;
+ service.setInterfaceUp(iface);
InterfaceConfiguration config = service.getInterfaceConfig(iface);
mLinkUp = config.isActive();
+ if (config != null && mHwAddr == null) {
+ mHwAddr = config.getHardwareAddress();
+ if (mHwAddr != null) {
+ mNetworkInfo.setExtraInfo(mHwAddr);
+ }
+ }
reconnect();
break;
}
@@ -239,9 +250,11 @@
* Re-enable connectivity to a network after a {@link #teardown()}.
*/
public boolean reconnect() {
- mTeardownRequested.set(false);
- runDhcp();
- return true;
+ if (mLinkUp) {
+ mTeardownRequested.set(false);
+ runDhcp();
+ }
+ return mLinkUp;
}
/**
diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java
index 7286f0d..2f43cb8 100644
--- a/core/java/android/net/NetworkInfo.java
+++ b/core/java/android/net/NetworkInfo.java
@@ -351,6 +351,18 @@
}
/**
+ * Set the extraInfo field.
+ * @param extraInfo an optional {@code String} providing addditional network state
+ * information passed up from the lower networking layers.
+ * @hide
+ */
+ public void setExtraInfo(String extraInfo) {
+ synchronized (this) {
+ this.mExtraInfo = extraInfo;
+ }
+ }
+
+ /**
* Report the reason an attempt to establish connectivity failed,
* if one is available.
* @return the reason for failure, or null if not available
diff --git a/core/java/android/os/IServiceManager.java b/core/java/android/os/IServiceManager.java
index 9a5ff47..7b11c28 100644
--- a/core/java/android/os/IServiceManager.java
+++ b/core/java/android/os/IServiceManager.java
@@ -45,7 +45,8 @@
* Place a new @a service called @a name into the service
* manager.
*/
- public void addService(String name, IBinder service) throws RemoteException;
+ public void addService(String name, IBinder service, boolean allowIsolated)
+ throws RemoteException;
/**
* Return a list of all currently running services.
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index cdf235d..6139296 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -119,7 +119,19 @@
* Last of application-specific UIDs starting at
* {@link #FIRST_APPLICATION_UID}.
*/
- public static final int LAST_APPLICATION_UID = 99999;
+ public static final int LAST_APPLICATION_UID = 19999;
+
+ /**
+ * First uid used for fully isolated sandboxed processes (with no permissions of their own)
+ * @hide
+ */
+ public static final int FIRST_ISOLATED_UID = 99000;
+
+ /**
+ * Last uid used for fully isolated sandboxed processes (with no permissions of their own)
+ * @hide
+ */
+ public static final int LAST_ISOLATED_UID = 99999;
/**
* Defines a secondary group id for access to the bluetooth hardware.
@@ -576,6 +588,15 @@
public static final native int myUid();
/**
+ * Returns whether the current process is in an isolated sandbox.
+ * @hide
+ */
+ public static final boolean isIsolated() {
+ int uid = UserId.getAppId(myUid());
+ return uid >= FIRST_ISOLATED_UID && uid <= LAST_ISOLATED_UID;
+ }
+
+ /**
* Returns the UID assigned to a particular user name, or -1 if there is
* none. If the given string consists of only numbers, it is converted
* directly to a uid.
diff --git a/core/java/android/os/ServiceManager.java b/core/java/android/os/ServiceManager.java
index 1af24f4a..13b8b66 100644
--- a/core/java/android/os/ServiceManager.java
+++ b/core/java/android/os/ServiceManager.java
@@ -69,7 +69,24 @@
*/
public static void addService(String name, IBinder service) {
try {
- getIServiceManager().addService(name, service);
+ getIServiceManager().addService(name, service, false);
+ } catch (RemoteException e) {
+ Log.e(TAG, "error in addService", e);
+ }
+ }
+
+ /**
+ * Place a new @a service called @a name into the service
+ * manager.
+ *
+ * @param name the name of the new service
+ * @param service the service object
+ * @param allowIsolated set to true to allow isolated sandboxed processes
+ * to access this service
+ */
+ public static void addService(String name, IBinder service, boolean allowIsolated) {
+ try {
+ getIServiceManager().addService(name, service, allowIsolated);
} catch (RemoteException e) {
Log.e(TAG, "error in addService", e);
}
diff --git a/core/java/android/os/ServiceManagerNative.java b/core/java/android/os/ServiceManagerNative.java
index 2aab0e6..43b5128 100644
--- a/core/java/android/os/ServiceManagerNative.java
+++ b/core/java/android/os/ServiceManagerNative.java
@@ -71,7 +71,8 @@
data.enforceInterface(IServiceManager.descriptor);
String name = data.readString();
IBinder service = data.readStrongBinder();
- addService(name, service);
+ boolean allowIsolated = data.readInt() != 0;
+ addService(name, service, allowIsolated);
return true;
}
@@ -136,13 +137,14 @@
return binder;
}
- public void addService(String name, IBinder service)
+ public void addService(String name, IBinder service, boolean allowIsolated)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IServiceManager.descriptor);
data.writeString(name);
data.writeStrongBinder(service);
+ data.writeInt(allowIsolated ? 1 : 0);
mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
reply.recycle();
data.recycle();
diff --git a/core/java/android/os/UserId.java b/core/java/android/os/UserId.java
index 4124d51..0da67d63 100644
--- a/core/java/android/os/UserId.java
+++ b/core/java/android/os/UserId.java
@@ -56,6 +56,11 @@
return getAppId(uid1) == getAppId(uid2);
}
+ public static final boolean isIsolated(int uid) {
+ uid = getAppId(uid);
+ return uid >= Process.FIRST_ISOLATED_UID && uid <= Process.LAST_ISOLATED_UID;
+ }
+
/**
* Returns the user id for a given uid.
* @hide
@@ -68,6 +73,10 @@
}
}
+ public static final int getCallingUserId() {
+ return getUserId(Binder.getCallingUid());
+ }
+
/**
* Returns the uid that is composed from the userId and the appId.
* @hide
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index cdb622c..fbf512c 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -16,6 +16,7 @@
package android.os.storage;
+import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -534,6 +535,7 @@
* @hide
*/
public String getVolumeState(String mountPoint) {
+ if (mMountService == null) return Environment.MEDIA_REMOVED;
try {
return mMountService.getVolumeState(mountPoint);
} catch (RemoteException e) {
@@ -547,6 +549,7 @@
* @hide
*/
public StorageVolume[] getVolumeList() {
+ if (mMountService == null) return new StorageVolume[0];
try {
Parcelable[] list = mMountService.getVolumeList();
if (list == null) return new StorageVolume[0];
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 375e5e4..0aad64a 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1412,7 +1412,7 @@
public static final int SCREEN_BRIGHTNESS_MODE_MANUAL = 0;
/**
- * SCREEN_BRIGHTNESS_MODE value for manual mode.
+ * SCREEN_BRIGHTNESS_MODE value for automatic mode.
*/
public static final int SCREEN_BRIGHTNESS_MODE_AUTOMATIC = 1;
@@ -1499,6 +1499,12 @@
public static final String VOLUME_BLUETOOTH_SCO = "volume_bluetooth_sco";
/**
+ * Master volume (float in the range 0.0f to 1.0f).
+ * @hide
+ */
+ public static final String VOLUME_MASTER = "volume_master";
+
+ /**
* Whether the notifications should use the ring volume (value of 1) or a separate
* notification volume (value of 0). In most cases, users will have this enabled so the
* notification and ringer volumes will be the same. However, power users can disable this
@@ -1830,6 +1836,12 @@
public static final String LOCKSCREEN_SOUNDS_ENABLED = "lockscreen_sounds_enabled";
/**
+ * Whether the lockscreen should be completely disabled.
+ * @hide
+ */
+ public static final String LOCKSCREEN_DISABLED = "lockscreen.disabled";
+
+ /**
* URI for the low battery sound file.
* @hide
*/
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 95a3cdc..43dfc81 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -1325,7 +1325,11 @@
sb.append("&"); //$NON-NLS-1$
break;
case '\'':
- sb.append("'"); //$NON-NLS-1$
+ //http://www.w3.org/TR/xhtml1
+ // The named character reference ' (the apostrophe, U+0027) was introduced in
+ // XML 1.0 but does not appear in HTML. Authors should therefore use ' instead
+ // of ' to work as expected in HTML 4 user agents.
+ sb.append("'"); //$NON-NLS-1$
break;
case '"':
sb.append("""); //$NON-NLS-1$
diff --git a/core/java/android/util/LongSparseArray.java b/core/java/android/util/LongSparseArray.java
index 1ec8be6..630e5f3 100644
--- a/core/java/android/util/LongSparseArray.java
+++ b/core/java/android/util/LongSparseArray.java
@@ -19,56 +19,50 @@
import com.android.internal.util.ArrayUtils;
/**
- * SparseArrays map longs to Objects. Unlike a normal array of Objects,
+ * SparseArray mapping longs to Objects. Unlike a normal array of Objects,
* there can be gaps in the indices. It is intended to be more efficient
* than using a HashMap to map Longs to Objects.
- *
- * @hide
*/
-public class LongSparseArray<E> {
+public class LongSparseArray<E> implements Cloneable {
private static final Object DELETED = new Object();
private boolean mGarbage = false;
+ private long[] mKeys;
+ private Object[] mValues;
+ private int mSize;
+
/**
- * Creates a new SparseArray containing no mappings.
+ * Creates a new LongSparseArray containing no mappings.
*/
public LongSparseArray() {
this(10);
}
/**
- * Creates a new SparseArray containing no mappings that will not
+ * Creates a new LongSparseArray containing no mappings that will not
* require any additional memory allocation to store the specified
* number of mappings.
*/
public LongSparseArray(int initialCapacity) {
- initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity);
+ initialCapacity = ArrayUtils.idealLongArraySize(initialCapacity);
mKeys = new long[initialCapacity];
mValues = new Object[initialCapacity];
mSize = 0;
}
-
- /**
- * @return A copy of all keys contained in the sparse array.
- */
- public long[] getKeys() {
- int length = mKeys.length;
- long[] result = new long[length];
- System.arraycopy(mKeys, 0, result, 0, length);
- return result;
- }
-
- /**
- * Sets all supplied keys to the given unique value.
- * @param keys Keys to set
- * @param uniqueValue Value to set all supplied keys to
- */
- public void setValues(long[] keys, E uniqueValue) {
- int length = keys.length;
- for (int i = 0; i < length; i++) {
- put(keys[i], uniqueValue);
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public LongSparseArray<E> clone() {
+ LongSparseArray<E> clone = null;
+ try {
+ clone = (LongSparseArray<E>) super.clone();
+ clone.mKeys = mKeys.clone();
+ clone.mValues = mValues.clone();
+ } catch (CloneNotSupportedException cnse) {
+ /* ignore */
}
+ return clone;
}
/**
@@ -83,6 +77,7 @@
* Gets the Object mapped from the specified key, or the specified Object
* if no such mapping has been made.
*/
+ @SuppressWarnings("unchecked")
public E get(long key, E valueIfKeyNotFound) {
int i = binarySearch(mKeys, 0, mSize, key);
@@ -114,6 +109,16 @@
delete(key);
}
+ /**
+ * Removes the mapping at the specified index.
+ */
+ public void removeAt(int index) {
+ if (mValues[index] != DELETED) {
+ mValues[index] = DELETED;
+ mGarbage = true;
+ }
+ }
+
private void gc() {
// Log.e("SparseArray", "gc start with " + mSize);
@@ -129,6 +134,7 @@
if (i != o) {
keys[o] = keys[i];
values[o] = val;
+ values[i] = null;
}
o++;
@@ -168,7 +174,7 @@
}
if (mSize >= mKeys.length) {
- int n = ArrayUtils.idealIntArraySize(mSize + 1);
+ int n = ArrayUtils.idealLongArraySize(mSize + 1);
long[] nkeys = new long[n];
Object[] nvalues = new Object[n];
@@ -194,7 +200,7 @@
}
/**
- * Returns the number of key-value mappings that this SparseArray
+ * Returns the number of key-value mappings that this LongSparseArray
* currently stores.
*/
public int size() {
@@ -208,7 +214,7 @@
/**
* Given an index in the range <code>0...size()-1</code>, returns
* the key from the <code>index</code>th key-value mapping that this
- * SparseArray stores.
+ * LongSparseArray stores.
*/
public long keyAt(int index) {
if (mGarbage) {
@@ -221,8 +227,9 @@
/**
* Given an index in the range <code>0...size()-1</code>, returns
* the value from the <code>index</code>th key-value mapping that this
- * SparseArray stores.
+ * LongSparseArray stores.
*/
+ @SuppressWarnings("unchecked")
public E valueAt(int index) {
if (mGarbage) {
gc();
@@ -234,7 +241,7 @@
/**
* Given an index in the range <code>0...size()-1</code>, sets a new
* value for the <code>index</code>th key-value mapping that this
- * SparseArray stores.
+ * LongSparseArray stores.
*/
public void setValueAt(int index, E value) {
if (mGarbage) {
@@ -278,7 +285,7 @@
}
/**
- * Removes all key-value mappings from this SparseArray.
+ * Removes all key-value mappings from this LongSparseArray.
*/
public void clear() {
int n = mSize;
@@ -308,7 +315,7 @@
int pos = mSize;
if (pos >= mKeys.length) {
- int n = ArrayUtils.idealIntArraySize(pos + 1);
+ int n = ArrayUtils.idealLongArraySize(pos + 1);
long[] nkeys = new long[n];
Object[] nvalues = new Object[n];
@@ -345,20 +352,4 @@
else
return ~high;
}
-
- private void checkIntegrity() {
- for (int i = 1; i < mSize; i++) {
- if (mKeys[i] <= mKeys[i - 1]) {
- for (int j = 0; j < mSize; j++) {
- Log.e("FAIL", j + ": " + mKeys[j] + " -> " + mValues[j]);
- }
-
- throw new RuntimeException();
- }
- }
- }
-
- private long[] mKeys;
- private Object[] mValues;
- private int mSize;
-}
\ No newline at end of file
+}
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index fa4dd25..1e92b43 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -723,6 +723,7 @@
@Override
public void drawPatch(Bitmap bitmap, byte[] chunks, RectF dst, Paint paint) {
+ if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
// Shaders are ignored when drawing patches
int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
final int nativePaint = paint == null ? 0 : paint.mNativePaint;
@@ -736,6 +737,7 @@
@Override
public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
+ if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
// Shaders are ignored when drawing bitmaps
int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
final int nativePaint = paint == null ? 0 : paint.mNativePaint;
@@ -748,6 +750,7 @@
@Override
public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
+ if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
// Shaders are ignored when drawing bitmaps
int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
final int nativePaint = paint == null ? 0 : paint.mNativePaint;
@@ -761,6 +764,7 @@
@Override
public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
+ if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
// Shaders are ignored when drawing bitmaps
int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
final int nativePaint = paint == null ? 0 : paint.mNativePaint;
@@ -784,6 +788,7 @@
@Override
public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
+ if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
// Shaders are ignored when drawing bitmaps
int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
final int nativePaint = paint == null ? 0 : paint.mNativePaint;
@@ -832,6 +837,7 @@
@Override
public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts,
int vertOffset, int[] colors, int colorOffset, Paint paint) {
+ if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
if (meshWidth < 0 || meshHeight < 0 || vertOffset < 0 || colorOffset < 0) {
throw new ArrayIndexOutOfBoundsException();
}
diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java
index 24a3066..9152cc3 100644
--- a/core/java/android/view/VolumePanel.java
+++ b/core/java/android/view/VolumePanel.java
@@ -91,6 +91,10 @@
private static final int MSG_VIBRATE = 4;
private static final int MSG_TIMEOUT = 5;
private static final int MSG_RINGER_MODE_CHANGED = 6;
+ private static final int MSG_MUTE_CHANGED = 7;
+
+ // Pseudo stream type for master volume
+ private static final int STREAM_MASTER = -100;
protected Context mContext;
private AudioManager mAudioManager;
@@ -148,7 +152,13 @@
R.string.volume_icon_description_notification,
R.drawable.ic_audio_notification,
R.drawable.ic_audio_notification_mute,
- true);
+ true),
+ // for now, use media resources for master volume
+ MasterStream(STREAM_MASTER,
+ R.string.volume_icon_description_media,
+ R.drawable.ic_audio_vol,
+ R.drawable.ic_audio_vol_mute,
+ false);
int streamType;
int descRes;
@@ -173,7 +183,8 @@
StreamResources.VoiceStream,
StreamResources.MediaStream,
StreamResources.NotificationStream,
- StreamResources.AlarmStream
+ StreamResources.AlarmStream,
+ StreamResources.MasterStream
};
/** Object that contains data for each slider */
@@ -195,6 +206,16 @@
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
mAudioService = volumeService;
+ // For now, only show master volume if master volume is supported
+ boolean useMasterVolume = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_useMasterVolume);
+ if (useMasterVolume) {
+ for (int i = 0; i < STREAMS.length; i++) {
+ StreamResources streamRes = STREAMS[i];
+ streamRes.show = (streamRes.streamType == STREAM_MASTER);
+ }
+ }
+
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = mView = inflater.inflate(R.layout.volume_adjust, null);
@@ -245,7 +266,7 @@
mVibrator = new Vibrator();
mVoiceCapable = context.getResources().getBoolean(R.bool.config_voice_capable);
- mShowCombinedVolumes = !mVoiceCapable;
+ mShowCombinedVolumes = !mVoiceCapable && !useMasterVolume;
// If we don't want to show multiple volumes, hide the settings button and divider
if (!mShowCombinedVolumes) {
mMoreButton.setVisibility(View.GONE);
@@ -274,7 +295,43 @@
}
private boolean isMuted(int streamType) {
- return mAudioManager.isStreamMute(streamType);
+ if (streamType == STREAM_MASTER) {
+ return mAudioService.isMasterMute();
+ } else {
+ return mAudioService.isStreamMute(streamType);
+ }
+ }
+
+ private int getStreamMaxVolume(int streamType) {
+ if (streamType == STREAM_MASTER) {
+ return mAudioService.getMasterMaxVolume();
+ } else {
+ return mAudioService.getStreamMaxVolume(streamType);
+ }
+ }
+
+ private int getStreamVolume(int streamType) {
+ if (streamType == STREAM_MASTER) {
+ return mAudioService.getMasterVolume();
+ } else {
+ return mAudioService.getStreamVolume(streamType);
+ }
+ }
+
+ private void setStreamVolume(int streamType, int index, int flags) {
+ if (streamType == STREAM_MASTER) {
+ mAudioService.setMasterVolume(index, flags);
+ } else {
+ mAudioService.setStreamVolume(streamType, index, flags);
+ }
+ }
+
+ private int getLastAudibleStreamVolume(int streamType) {
+ if (streamType == STREAM_MASTER) {
+ return mAudioService.getLastAudibleMasterVolume();
+ } else {
+ return mAudioService.getLastAudibleStreamVolume(streamType);
+ }
}
private void createSliders() {
@@ -301,7 +358,7 @@
sc.seekbarView = (SeekBar) sc.group.findViewById(R.id.seekbar);
int plusOne = (streamType == AudioSystem.STREAM_BLUETOOTH_SCO ||
streamType == AudioSystem.STREAM_VOICE_CALL) ? 1 : 0;
- sc.seekbarView.setMax(mAudioManager.getStreamMaxVolume(streamType) + plusOne);
+ sc.seekbarView.setMax(getStreamMaxVolume(streamType) + plusOne);
sc.seekbarView.setOnSeekBarChangeListener(this);
sc.seekbarView.setTag(sc);
mStreamControls.put(streamType, sc);
@@ -342,7 +399,7 @@
/** Update the mute and progress state of a slider */
private void updateSlider(StreamControl sc) {
- sc.seekbarView.setProgress(mAudioManager.getLastAudibleStreamVolume(sc.streamType));
+ sc.seekbarView.setProgress(getLastAudibleStreamVolume(sc.streamType));
final boolean muted = isMuted(sc.streamType);
sc.icon.setImageResource(muted ? sc.iconMuteRes : sc.iconRes);
if (sc.streamType == AudioManager.STREAM_RING && muted
@@ -390,6 +447,23 @@
obtainMessage(MSG_VOLUME_CHANGED, streamType, flags).sendToTarget();
}
+ public void postMasterVolumeChanged(int flags) {
+ postVolumeChanged(STREAM_MASTER, flags);
+ }
+
+ public void postMuteChanged(int streamType, int flags) {
+ if (hasMessages(MSG_VOLUME_CHANGED)) return;
+ if (mStreamControls == null) {
+ createSliders();
+ }
+ removeMessages(MSG_FREE_RESOURCES);
+ obtainMessage(MSG_MUTE_CHANGED, streamType, flags).sendToTarget();
+ }
+
+ public void postMasterMuteChanged(int flags) {
+ postMuteChanged(STREAM_MASTER, flags);
+ }
+
/**
* Override this if you have other work to do when the volume changes (for
* example, vibrating, playing a sound, etc.). Make sure to call through to
@@ -423,10 +497,22 @@
resetTimeout();
}
+ protected void onMuteChanged(int streamType, int flags) {
+
+ if (LOGD) Log.d(TAG, "onMuteChanged(streamType: " + streamType + ", flags: " + flags + ")");
+
+ StreamControl sc = mStreamControls.get(streamType);
+ if (sc != null) {
+ sc.icon.setImageResource(isMuted(sc.streamType) ? sc.iconMuteRes : sc.iconRes);
+ }
+
+ onVolumeChanged(streamType, flags);
+ }
+
protected void onShowVolumeChanged(int streamType, int flags) {
- int index = mAudioService.isStreamMute(streamType) ?
- mAudioService.getLastAudibleStreamVolume(streamType)
- : mAudioService.getStreamVolume(streamType);
+ int index = isMuted(streamType) ?
+ getLastAudibleStreamVolume(streamType)
+ : getStreamVolume(streamType);
mRingIsSilent = false;
@@ -437,7 +523,7 @@
// get max volume for progress bar
- int max = mAudioService.getStreamMaxVolume(streamType);
+ int max = getStreamMaxVolume(streamType);
switch (streamType) {
@@ -571,6 +657,7 @@
* Lock on this VolumePanel instance as long as you use the returned ToneGenerator.
*/
private ToneGenerator getOrCreateToneGenerator(int streamType) {
+ if (streamType == STREAM_MASTER) return null;
synchronized (this) {
if (mToneGenerators[streamType] == null) {
try {
@@ -620,6 +707,11 @@
break;
}
+ case MSG_MUTE_CHANGED: {
+ onMuteChanged(msg.arg1, msg.arg2);
+ break;
+ }
+
case MSG_FREE_RESOURCES: {
onFreeResources();
break;
@@ -671,8 +763,8 @@
final Object tag = seekBar.getTag();
if (fromUser && tag instanceof StreamControl) {
StreamControl sc = (StreamControl) tag;
- if (mAudioManager.getStreamVolume(sc.streamType) != progress) {
- mAudioManager.setStreamVolume(sc.streamType, progress, 0);
+ if (getStreamVolume(sc.streamType) != progress) {
+ setStreamVolume(sc.streamType, progress, 0);
}
}
resetTimeout();
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 0985e14..7171b58 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1593,6 +1593,27 @@
}
/**
+ * Force switch to the next input method and subtype. If there is no IME enabled except
+ * current IME and subtype, do nothing.
+ * @param imeToken Supplies the identifying token given to an input method when it was started,
+ * which allows it to perform this operation on itself.
+ * @param onlyCurrentIme if true, the framework will find the next subtype which
+ * belongs to the current IME
+ * @return true if the current input method and subtype was successfully switched to the next
+ * input method and subtype.
+ */
+ public boolean switchToNextInputMethod(IBinder imeToken, boolean onlyCurrentIme) {
+ synchronized (mH) {
+ try {
+ return mService.switchToNextInputMethod(imeToken, onlyCurrentIme);
+ } catch (RemoteException e) {
+ Log.w(TAG, "IME died: " + mCurId, e);
+ return false;
+ }
+ }
+ }
+
+ /**
* Set additional input method subtypes. Only a process which shares the same uid with the IME
* can add additional input method subtypes to the IME.
* Please note that a subtype's status is stored in the system.
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index b4c38db..c463b40 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -1156,8 +1156,13 @@
}
/**
- * Tell the WebView to load image resources automatically.
- * @param flag True if the WebView should load images automatically.
+ * Sets whether the WebView should load image resources. Note that this method
+ * controls loading of all images, including those embedded using the data
+ * URI scheme. Use {@link #setBlockNetworkImage} to control loading only
+ * of images specified using network URI schemes. Note that if the value of this
+ * setting is changed from false to true, all images resources referenced
+ * by content currently displayed by the WebView are loaded automatically.
+ * @param flag Whether the WebView should load image resources.
*/
public synchronized void setLoadsImagesAutomatically(boolean flag) {
if (mLoadsImagesAutomatically != flag) {
@@ -1167,20 +1172,26 @@
}
/**
- * Return true if the WebView will load image resources automatically.
- * The default is true.
- * @return True if the WebView loads images automatically.
+ * Returns true if the WebView loads image resources. This includes
+ * images embedded using the data URI scheme. The default is true.
+ * @return True if the WebView loads image resources.
*/
public synchronized boolean getLoadsImagesAutomatically() {
return mLoadsImagesAutomatically;
}
/**
- * Tell the WebView to block network images. This is only checked when
- * {@link #getLoadsImagesAutomatically} is true. If you set the value to
- * false, images will automatically be loaded. Use this api to reduce
- * bandwidth only. Use {@link #setBlockNetworkLoads} if possible.
- * @param flag True if the WebView should block network images.
+ * Sets whether the WebView should not load image resources from the
+ * network (resources accessed via http and https URI schemes). Note
+ * that this method has no effect unless
+ * {@link #getLoadsImagesAutomatically} returns true. Also note that
+ * disabling all network loads using {@link #setBlockNetworkLoads}
+ * will also prevent network images from loading, even if this flag is set
+ * to false. When the value of this setting is changed from true to false,
+ * network images resources referenced by content currently displayed by
+ * the WebView are fetched automatically.
+ * @param flag Whether the WebView should not load image resources from
+ * the network.
* @see #setBlockNetworkLoads
*/
public synchronized void setBlockNetworkImage(boolean flag) {
@@ -1191,20 +1202,27 @@
}
/**
- * Return true if the WebView will block network images. The default is
- * false.
- * @return True if the WebView blocks network images.
+ * Returns true if the WebView does not load image resources from the network.
+ * The default is false.
+ * @return True if the WebView does not load image resources from the network.
*/
public synchronized boolean getBlockNetworkImage() {
return mBlockNetworkImage;
}
/**
- * Tell the WebView to block all network load requests. If you set the
- * value to false, you must call {@link android.webkit.WebView#reload} to
- * fetch remote resources. This flag supercedes the value passed to
- * {@link #setBlockNetworkImage}.
- * @param flag True if the WebView should block all network loads.
+ * Sets whether the WebView should not load resources from the network.
+ * Use {@link #setBlockNetworkImage} to only avoid loading
+ * image resources. Note that if the value of this setting is
+ * changed from true to false, network resources referenced by content
+ * currently displayed by the WebView are not fetched until
+ * {@link android.webkit.WebView#reload} is called.
+ * If the application does not have the
+ * {@link android.Manifest.permission#INTERNET} permission, attempts to set
+ * a value of false will cause a {@link java.lang.SecurityException}
+ * to be thrown.
+ * @param flag Whether the WebView should not load any resources
+ * from the network.
* @see android.webkit.WebView#reload
*/
public synchronized void setBlockNetworkLoads(boolean flag) {
@@ -1216,9 +1234,11 @@
}
/**
- * Return true if the WebView will block all network loads. The default is
- * false.
- * @return True if the WebView blocks all network loads.
+ * Returns true if the WebView does not load any resources from the network.
+ * The default value is false if the application has the
+ * {@link android.Manifest.permission#INTERNET} permission, otherwise it is
+ * true.
+ * @return True if the WebView does not load any resources from the network.
*/
public synchronized boolean getBlockNetworkLoads() {
return mBlockNetworkLoads;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 971d910..99349b0 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -1205,6 +1205,7 @@
if (imm != null) imm.restartInput(this);
}
+ mTextDisplayListIsValid = false;
prepareCursorControllers();
// start or stop the cursor blinking as appropriate
@@ -2310,6 +2311,7 @@
public void setHighlightColor(int color) {
if (mHighlightColor != color) {
mHighlightColor = color;
+ mTextDisplayListIsValid = false;
invalidate();
}
}
@@ -2330,6 +2332,7 @@
mShadowDx = dx;
mShadowDy = dy;
+ mTextDisplayListIsValid = false;
invalidate();
}
@@ -2821,6 +2824,7 @@
}
}
if (inval) {
+ mTextDisplayListIsValid = false;
invalidate();
}
}
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 683aca5..5d80b79 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -67,6 +67,7 @@
InputMethodSubtype getCurrentInputMethodSubtype();
boolean setCurrentInputMethodSubtype(in InputMethodSubtype subtype);
boolean switchToLastInputMethod(in IBinder token);
+ boolean switchToNextInputMethod(in IBinder token, boolean onlyCurrentIme);
boolean setInputMethodEnabled(String id, boolean enabled);
oneway void setAdditionalInputMethodSubtypes(String id, in InputMethodSubtype[] subtypes);
}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 39b84bb..78e8df3 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -126,6 +126,7 @@
android_media_ToneGenerator.cpp \
android_hardware_Camera.cpp \
android_hardware_SensorManager.cpp \
+ android_hardware_SerialPort.cpp \
android_hardware_UsbDevice.cpp \
android_hardware_UsbDeviceConnection.cpp \
android_hardware_UsbRequest.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 8a3063f..3067e75 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -76,6 +76,7 @@
extern int register_android_hardware_Camera(JNIEnv *env);
extern int register_android_hardware_SensorManager(JNIEnv *env);
+extern int register_android_hardware_SerialPort(JNIEnv *env);
extern int register_android_hardware_UsbDevice(JNIEnv *env);
extern int register_android_hardware_UsbDeviceConnection(JNIEnv *env);
extern int register_android_hardware_UsbRequest(JNIEnv *env);
@@ -1157,6 +1158,7 @@
REG_JNI(register_com_android_internal_os_ZygoteInit),
REG_JNI(register_android_hardware_Camera),
REG_JNI(register_android_hardware_SensorManager),
+ REG_JNI(register_android_hardware_SerialPort),
REG_JNI(register_android_hardware_UsbDevice),
REG_JNI(register_android_hardware_UsbDeviceConnection),
REG_JNI(register_android_hardware_UsbRequest),
diff --git a/core/jni/android_backup_BackupDataOutput.cpp b/core/jni/android_backup_BackupDataOutput.cpp
index f4b5dca..abe0104 100644
--- a/core/jni/android_backup_BackupDataOutput.cpp
+++ b/core/jni/android_backup_BackupDataOutput.cpp
@@ -52,7 +52,6 @@
if (keyUTF == NULL) {
return -1;
}
-
err = writer->WriteEntityHeader(String8(keyUTF), dataSize);
env->ReleaseStringUTFChars(key, keyUTF);
diff --git a/core/jni/android_hardware_SerialPort.cpp b/core/jni/android_hardware_SerialPort.cpp
new file mode 100644
index 0000000..7f40a5c
--- /dev/null
+++ b/core/jni/android_hardware_SerialPort.cpp
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SerialPortJNI"
+
+#include "utils/Log.h"
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <termios.h>
+
+using namespace android;
+
+static jfieldID field_context;
+
+static void
+android_hardware_SerialPort_open(JNIEnv *env, jobject thiz, jobject fileDescriptor, jint speed)
+{
+ switch (speed) {
+ case 50:
+ speed = B50;
+ break;
+ case 75:
+ speed = B75;
+ break;
+ case 110:
+ speed = B110;
+ break;
+ case 134:
+ speed = B134;
+ break;
+ case 150:
+ speed = B150;
+ break;
+ case 200:
+ speed = B200;
+ break;
+ case 300:
+ speed = B300;
+ break;
+ case 600:
+ speed = B600;
+ break;
+ case 1200:
+ speed = B1200;
+ break;
+ case 1800:
+ speed = B1800;
+ break;
+ case 2400:
+ speed = B2400;
+ break;
+ case 4800:
+ speed = B4800;
+ break;
+ case 9600:
+ speed = B9600;
+ break;
+ case 19200:
+ speed = B19200;
+ break;
+ case 38400:
+ speed = B38400;
+ break;
+ case 57600:
+ speed = B57600;
+ break;
+ case 115200:
+ speed = B115200;
+ break;
+ case 230400:
+ speed = B230400;
+ break;
+ case 460800:
+ speed = B460800;
+ break;
+ case 500000:
+ speed = B500000;
+ break;
+ case 576000:
+ speed = B576000;
+ break;
+ case 921600:
+ speed = B921600;
+ break;
+ case 1000000:
+ speed = B1000000;
+ break;
+ case 1152000:
+ speed = B1152000;
+ break;
+ case 1500000:
+ speed = B1500000;
+ break;
+ case 2000000:
+ speed = B2000000;
+ break;
+ case 2500000:
+ speed = B2500000;
+ break;
+ case 3000000:
+ speed = B3000000;
+ break;
+ case 3500000:
+ speed = B3500000;
+ break;
+ case 4000000:
+ speed = B4000000;
+ break;
+ default:
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "Unsupported serial port speed");
+ return;
+ }
+
+ int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
+ // duplicate the file descriptor, since ParcelFileDescriptor will eventually close its copy
+ fd = dup(fd);
+ if (fd < 0) {
+ jniThrowException(env, "java/io/IOException", "Could not open serial port");
+ return;
+ }
+ env->SetIntField(thiz, field_context, fd);
+
+ struct termios tio;
+ if (tcgetattr(fd, &tio))
+ memset(&tio, 0, sizeof(tio));
+
+ tio.c_cflag = speed | CS8 | CLOCAL | CREAD;
+ // Disable output processing, including messing with end-of-line characters.
+ tio.c_oflag &= ~OPOST;
+ tio.c_iflag = IGNPAR;
+ tio.c_lflag = 0; /* turn of CANON, ECHO*, etc */
+ /* no timeout but request at least one character per read */
+ tio.c_cc[VTIME] = 0;
+ tio.c_cc[VMIN] = 1;
+ tcsetattr(fd, TCSANOW, &tio);
+ tcflush(fd, TCIFLUSH);
+}
+
+static void
+android_hardware_SerialPort_close(JNIEnv *env, jobject thiz)
+{
+ int fd = env->GetIntField(thiz, field_context);
+ close(fd);
+ env->SetIntField(thiz, field_context, -1);
+}
+
+static jint
+android_hardware_SerialPort_read_array(JNIEnv *env, jobject thiz, jbyteArray buffer, jint length)
+{
+ int fd = env->GetIntField(thiz, field_context);
+ jbyte* buf = (jbyte *)malloc(length);
+ if (!buf) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+ return -1;
+ }
+
+ int ret = read(fd, buf, length);
+ if (ret > 0) {
+ // copy data from native buffer to Java buffer
+ env->SetByteArrayRegion(buffer, 0, ret, buf);
+ }
+
+ free(buf);
+ if (ret < 0)
+ jniThrowException(env, "java/io/IOException", NULL);
+ return ret;
+}
+
+static jint
+android_hardware_SerialPort_read_direct(JNIEnv *env, jobject thiz, jobject buffer, jint length)
+{
+ int fd = env->GetIntField(thiz, field_context);
+
+ jbyte* buf = (jbyte *)env->GetDirectBufferAddress(buffer);
+ if (!buf) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "ByteBuffer not direct");
+ return -1;
+ }
+
+ int ret = read(fd, buf, length);
+ if (ret < 0)
+ jniThrowException(env, "java/io/IOException", NULL);
+ return ret;
+}
+
+static void
+android_hardware_SerialPort_write_array(JNIEnv *env, jobject thiz, jbyteArray buffer, jint length)
+{
+ int fd = env->GetIntField(thiz, field_context);
+ jbyte* buf = (jbyte *)malloc(length);
+ if (!buf) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+ return;
+ }
+ env->GetByteArrayRegion(buffer, 0, length, buf);
+
+ jint ret = write(fd, buf, length);
+ free(buf);
+ if (ret < 0)
+ jniThrowException(env, "java/io/IOException", NULL);
+}
+
+static void
+android_hardware_SerialPort_write_direct(JNIEnv *env, jobject thiz, jobject buffer, jint length)
+{
+ int fd = env->GetIntField(thiz, field_context);
+
+ jbyte* buf = (jbyte *)env->GetDirectBufferAddress(buffer);
+ if (!buf) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "ByteBuffer not direct");
+ return;
+ }
+ int ret = write(fd, buf, length);
+ if (ret < 0)
+ jniThrowException(env, "java/io/IOException", NULL);
+}
+
+static void
+android_hardware_SerialPort_send_break(JNIEnv *env, jobject thiz)
+{
+ int fd = env->GetIntField(thiz, field_context);
+ tcsendbreak(fd, 0);
+}
+
+static JNINativeMethod method_table[] = {
+ {"native_open", "(Ljava/io/FileDescriptor;I)V",
+ (void *)android_hardware_SerialPort_open},
+ {"native_close", "()V", (void *)android_hardware_SerialPort_close},
+ {"native_read_array", "([BI)I",
+ (void *)android_hardware_SerialPort_read_array},
+ {"native_read_direct", "(Ljava/nio/ByteBuffer;I)I",
+ (void *)android_hardware_SerialPort_read_direct},
+ {"native_write_array", "([BI)V",
+ (void *)android_hardware_SerialPort_write_array},
+ {"native_write_direct", "(Ljava/nio/ByteBuffer;I)V",
+ (void *)android_hardware_SerialPort_write_direct},
+ {"native_send_break", "()V", (void *)android_hardware_SerialPort_send_break},
+};
+
+int register_android_hardware_SerialPort(JNIEnv *env)
+{
+ jclass clazz = env->FindClass("android/hardware/SerialPort");
+ if (clazz == NULL) {
+ ALOGE("Can't find android/hardware/SerialPort");
+ return -1;
+ }
+ field_context = env->GetFieldID(clazz, "mNativeContext", "I");
+ if (field_context == NULL) {
+ ALOGE("Can't find SerialPort.mNativeContext");
+ return -1;
+ }
+
+ return AndroidRuntime::registerNativeMethods(env, "android/hardware/SerialPort",
+ method_table, NELEM(method_table));
+}
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 6b4c5e8..31c5ed4 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -204,6 +204,38 @@
return index;
}
+static int
+android_media_AudioSystem_setMasterVolume(JNIEnv *env, jobject thiz, jfloat value)
+{
+ return check_AudioSystem_Command(AudioSystem::setMasterVolume(value));
+}
+
+static jfloat
+android_media_AudioSystem_getMasterVolume(JNIEnv *env, jobject thiz)
+{
+ float value;
+ if (AudioSystem::getMasterVolume(&value) != NO_ERROR) {
+ value = -1.0;
+ }
+ return value;
+}
+
+static int
+android_media_AudioSystem_setMasterMute(JNIEnv *env, jobject thiz, jboolean mute)
+{
+ return check_AudioSystem_Command(AudioSystem::setMasterMute(mute));
+}
+
+static jfloat
+android_media_AudioSystem_getMasterMute(JNIEnv *env, jobject thiz)
+{
+ bool mute;
+ if (AudioSystem::getMasterMute(&mute) != NO_ERROR) {
+ mute = false;
+ }
+ return mute;
+}
+
static jint
android_media_AudioSystem_getDevicesForStream(JNIEnv *env, jobject thiz, jint stream)
{
@@ -226,6 +258,10 @@
{"initStreamVolume", "(III)I", (void *)android_media_AudioSystem_initStreamVolume},
{"setStreamVolumeIndex","(III)I", (void *)android_media_AudioSystem_setStreamVolumeIndex},
{"getStreamVolumeIndex","(II)I", (void *)android_media_AudioSystem_getStreamVolumeIndex},
+ {"setMasterVolume", "(F)I", (void *)android_media_AudioSystem_setMasterVolume},
+ {"getMasterVolume", "()F", (void *)android_media_AudioSystem_getMasterVolume},
+ {"setMasterMute", "(Z)I", (void *)android_media_AudioSystem_setMasterMute},
+ {"getMasterMute", "()Z", (void *)android_media_AudioSystem_getMasterMute},
{"getDevicesForStream", "(I)I", (void *)android_media_AudioSystem_getDevicesForStream},
};
diff --git a/core/jni/android_media_ToneGenerator.cpp b/core/jni/android_media_ToneGenerator.cpp
index 26e82aa..0a337fae 100644
--- a/core/jni/android_media_ToneGenerator.cpp
+++ b/core/jni/android_media_ToneGenerator.cpp
@@ -39,7 +39,7 @@
static fields_t fields;
static jboolean android_media_ToneGenerator_startTone(JNIEnv *env, jobject thiz, jint toneType, jint durationMs) {
- ALOGV("android_media_ToneGenerator_startTone: %x\n", (int)thiz);
+ ALOGV("android_media_ToneGenerator_startTone: %x", (int)thiz);
ToneGenerator *lpToneGen = (ToneGenerator *)env->GetIntField(thiz,
fields.context);
@@ -52,12 +52,12 @@
}
static void android_media_ToneGenerator_stopTone(JNIEnv *env, jobject thiz) {
- ALOGV("android_media_ToneGenerator_stopTone: %x\n", (int)thiz);
+ ALOGV("android_media_ToneGenerator_stopTone: %x", (int)thiz);
ToneGenerator *lpToneGen = (ToneGenerator *)env->GetIntField(thiz,
fields.context);
- ALOGV("ToneGenerator lpToneGen: %x\n", (unsigned int)lpToneGen);
+ ALOGV("ToneGenerator lpToneGen: %x", (unsigned int)lpToneGen);
if (lpToneGen == NULL) {
jniThrowRuntimeException(env, "Method called after release()");
return;
@@ -68,13 +68,11 @@
static void android_media_ToneGenerator_release(JNIEnv *env, jobject thiz) {
ToneGenerator *lpToneGen = (ToneGenerator *)env->GetIntField(thiz,
fields.context);
- ALOGV("android_media_ToneGenerator_release lpToneGen: %x\n", (int)lpToneGen);
+ ALOGV("android_media_ToneGenerator_release lpToneGen: %x", (int)lpToneGen);
env->SetIntField(thiz, fields.context, 0);
- if (lpToneGen) {
- delete lpToneGen;
- }
+ delete lpToneGen;
}
static void android_media_ToneGenerator_native_setup(JNIEnv *env, jobject thiz,
@@ -83,17 +81,17 @@
env->SetIntField(thiz, fields.context, 0);
- ALOGV("android_media_ToneGenerator_native_setup jobject: %x\n", (int)thiz);
+ ALOGV("android_media_ToneGenerator_native_setup jobject: %x", (int)thiz);
if (lpToneGen == NULL) {
- ALOGE("ToneGenerator creation failed \n");
+ ALOGE("ToneGenerator creation failed");
jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
return;
}
- ALOGV("ToneGenerator lpToneGen: %x\n", (unsigned int)lpToneGen);
+ ALOGV("ToneGenerator lpToneGen: %x", (unsigned int)lpToneGen);
if (!lpToneGen->isInited()) {
- ALOGE("ToneGenerator init failed \n");
+ ALOGE("ToneGenerator init failed");
jniThrowRuntimeException(env, "Init failed");
return;
}
@@ -101,18 +99,18 @@
// Stow our new C++ ToneGenerator in an opaque field in the Java object.
env->SetIntField(thiz, fields.context, (int)lpToneGen);
- ALOGV("ToneGenerator fields.context: %x\n", env->GetIntField(thiz, fields.context));
+ ALOGV("ToneGenerator fields.context: %x", env->GetIntField(thiz, fields.context));
}
static void android_media_ToneGenerator_native_finalize(JNIEnv *env,
jobject thiz) {
- ALOGV("android_media_ToneGenerator_native_finalize jobject: %x\n", (int)thiz);
+ ALOGV("android_media_ToneGenerator_native_finalize jobject: %x", (int)thiz);
ToneGenerator *lpToneGen = (ToneGenerator *)env->GetIntField(thiz,
fields.context);
- if (lpToneGen) {
- ALOGV("delete lpToneGen: %x\n", (int)lpToneGen);
+ if (lpToneGen != NULL) {
+ ALOGV("delete lpToneGen: %p", lpToneGen);
delete lpToneGen;
}
}
diff --git a/core/jni/android_view_Display.cpp b/core/jni/android_view_Display.cpp
index 366a52e..f076cc8 100644
--- a/core/jni/android_view_Display.cpp
+++ b/core/jni/android_view_Display.cpp
@@ -28,6 +28,7 @@
#include <android_runtime/AndroidRuntime.h>
#include <utils/misc.h>
#include <utils/Log.h>
+#include <cutils/properties.h>
// ----------------------------------------------------------------------------
@@ -44,6 +45,7 @@
jfieldID ydpi;
};
static offsets_t offsets;
+static bool headless = false;
// ----------------------------------------------------------------------------
@@ -51,10 +53,19 @@
JNIEnv* env, jobject clazz, jint dpy)
{
DisplayInfo info;
- status_t err = SurfaceComposerClient::getDisplayInfo(DisplayID(dpy), &info);
- if (err < 0) {
- jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
- return;
+ if (headless) {
+ // initialize dummy display with reasonable values
+ info.pixelFormatInfo.format = 1; // RGB_8888
+ info.fps = 60;
+ info.density = 160;
+ info.xdpi = 160;
+ info.ydpi = 160;
+ } else {
+ status_t err = SurfaceComposerClient::getDisplayInfo(DisplayID(dpy), &info);
+ if (err < 0) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return;
+ }
}
env->SetIntField(clazz, offsets.pixelFormat,info.pixelFormatInfo.format);
env->SetFloatField(clazz, offsets.fps, info.fps);
@@ -66,6 +77,7 @@
static jint android_view_Display_getRawWidthNative(
JNIEnv* env, jobject clazz)
{
+ if (headless) return 640;
DisplayID dpy = env->GetIntField(clazz, offsets.display);
return SurfaceComposerClient::getDisplayWidth(dpy);
}
@@ -73,6 +85,7 @@
static jint android_view_Display_getRawHeightNative(
JNIEnv* env, jobject clazz)
{
+ if (headless) return 480;
DisplayID dpy = env->GetIntField(clazz, offsets.display);
return SurfaceComposerClient::getDisplayHeight(dpy);
}
@@ -80,6 +93,7 @@
static jint android_view_Display_getOrientation(
JNIEnv* env, jobject clazz)
{
+ if (headless) return 0; // Surface.ROTATION_0
DisplayID dpy = env->GetIntField(clazz, offsets.display);
return SurfaceComposerClient::getDisplayOrientation(dpy);
}
@@ -87,6 +101,7 @@
static jint android_view_Display_getDisplayCount(
JNIEnv* env, jclass clazz)
{
+ if (headless) return 1;
return SurfaceComposerClient::getNumberOfDisplays();
}
@@ -113,6 +128,12 @@
void nativeClassInit(JNIEnv* env, jclass clazz)
{
+ char value[PROPERTY_VALUE_MAX];
+
+ property_get("ro.config.headless", value, "0");
+ if (strcmp(value, "1") == 0)
+ headless = true;
+
offsets.display = env->GetFieldID(clazz, "mDisplay", "I");
offsets.pixelFormat = env->GetFieldID(clazz, "mPixelFormat", "I");
offsets.fps = env->GetFieldID(clazz, "mRefreshRate", "F");
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 97658a1..68c919e 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -717,6 +717,13 @@
android:label="@string/permlab_removeTasks"
android:description="@string/permdesc_removeTasks" />
+ <!-- @hide Change the screen compatibility mode of applications -->
+ <permission android:name="android.permission.SET_SCREEN_COMPATIBILITY"
+ android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+ android:protectionLevel="signature"
+ android:label="@string/permlab_setScreenCompatibility"
+ android:description="@string/permdesc_setScreenCompatibility" />
+
<!-- Allows an application to modify the current configuration, such
as locale. -->
<permission android:name="android.permission.CHANGE_CONFIGURATION"
@@ -1507,6 +1514,13 @@
android:description="@string/permdesc_bindPackageVerifier"
android:protectionLevel="signature" />
+ <!-- Allows applications to access serial ports via the SerialManager.
+ @hide -->
+ <permission android:name="android.permission.SERIAL_PORT"
+ android:label="@string/permlab_serialPort"
+ android:description="@string/permdesc_serialPort"
+ android:protectionLevel="normal" />
+
<!-- The system process is explicitly the only one allowed to launch the
confirmation UI for full backup/restore -->
<uses-permission android:name="android.permission.CONFIRM_FULL_BACKUP"/>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index f21c6b8..96c125c 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Laat die program toe om take na die voorgrond en agtergrond te skuif. Kwaadwillige programme kan hulself sonder jou beheer na vore dwing."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"stop lopende programme"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Laat die program toe om take te verwyder en hul programme te dood. Kwaadwillige programme kan die gedrag van ander programme ontwrig."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"aktiveer programontfouting"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Laat die program toe om ontfouting vir \'n ander program af te skakel. Kwaadwillige programme kan dit dalk gebruik om ander programme te dood."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"Verander jou UI-instellings"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 9b32c0d..52b690d 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"ወደ ግንባር ዎይ እና ዳራ ስራዎችን ለማንቀሳቀስ ለመተግበሪያው ይፈቅዳሉ፡፡ ያለአንተ ቁጥጥር ተንኮል አዘል መተግበሪያዎች ራሳቸውን ወደፊት መምጣት ሊያስገድዱ ይችላሉ፡፡"</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"የአሂድ ትግበራዎች አቁም"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"ተግባሮችን ለማስወገድ እና መተግበሪያዎቻቸውን ለመግደል ለመተግበሪያ ይፈቅዳል። ጎጂ የሆኑ መተግበሪያዎች የሌሎችን መተግበሪያዎችን ባህሪ ሊያውኩ ይችላሉ።"</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"የትግበራ ማረሚያ አንቃ"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"ለሌላ መተግበሪያ አርምን አብራ ለመተግበሪያው ይፈቅዳሉ። ሌሎች መተግበሪያዎች ለመግደል ተንኮል አዘል መተግበሪያዎች ይሄንን ሊጠቀሙት ይችላሉ።"</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"የUI ቅንብሮችን ለውጥ"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index b8cd094..2c02f66 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"للسماح لتطبيق ما بنقل المهام إلى المقدمة والخلفية. قد تفرض التطبيقات الضارة نفسها إلى المقدمة بدون تحكم منك."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"إيقاف التطبيقات التي قيد التشغيل"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"للسماح للتطبيق بإزالة المهام وإنهاء تطبيقاتها. قد تعطل التطبيقات الضارة عمل التطبيقات الأخرى."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"تمكين تصحيح أخطاء التطبيق"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"للسماح للتطبيق بتشغيل تصحيح الأخطاء لتطبيق آخر. قد تستخدم التطبيقات الضارة هذا لإنهاء التطبيقات الأخرى."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"تغيير إعدادات واجهة المستخدم"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 8479324..d17447e6 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Дазваляе прыкладанням перамяшчаць заданні на пярэдні план і фон. Шкоднасныя прыкладанні могуць прымусова рабіць сябе асноўнымі без вашага ведама."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"спыніць запушчаныя прыкладанні"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Дазваляе прыкладанням выдаляць заданні і спыняць прыкладанні, якія іх выкарыстоўваюць. Шкоднасныя прыкладаннi могуць перашкодзiць працы іншых прыкладанняў."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"уключыць адладку прыкладання"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Дазваляе прыкладанням уключаць адладку для іншага прыкладання. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб спыняць іншыя прыкладанні."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"змяняць налады карыстальніцкага інтэрфейса"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 6bec103..5c54a60 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Разрешава на приложението да прехвърля задачи на преден и на заден план. Злонамерените приложения могат сами да се изведат на преден план без ваша намеса."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"спиране на изпълняваните приложения"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Разрешава на приложението да премахва задачи и да прекратява приложенията им. Злонамерените приложения могат да нарушат поведението на други приложения."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"активиране на отстраняването на грешки в приложения"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Разрешава на приложението да включва отстраняването на грешки за друго приложение. Злонамерените приложения могат да използват това, за да прекратят други приложения."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"промяна на настройките ви за потребителския интерфейс"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 8dced70..6faa7ff 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Permet que l\'aplicació desplaci tasques en primer o segon pla. Les aplicacions malicioses poden aparèixer en primer pla sense el teu consentiment."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"atura les aplicacions que s\'estan executant"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Permet que l\'aplicació elimini tasques i finalitzi les seves aplicacions. Les aplicacions malicioses poden alterar el comportament d\'altres aplicacions."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"activa la depuració d\'aplicacions"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Permet que una aplicació activi la depuració per a una altra aplicació. Les aplicacions malicioses poden utilitzar aquesta funció per finalitzar altres aplicacions."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"canviar la configuració de la IU"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index e21de4b..d0cdd0d 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Umožňuje aplikaci přesunout úlohy na popředí nebo pozadí. Škodlivé aplikace mohou vynutit zobrazení na popředí bez vašeho svolení."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"zastavení činnosti aplikací"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Umožňuje aplikaci odstranit úlohy a ukončit jejich aplikace. Škodlivé aplikace mohou narušit chování ostatních aplikací."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"povolení ladění aplikací"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Umožňuje aplikaci zapnout ladění jiné aplikace. Škodlivé aplikace mohou toto oprávnění použít k ukončení ostatních aplikací."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"změna vašeho nastavení uživatelského rozhraní"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 1175cbb..44a7707 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Tillader, at appen kan flytte opgaver til forgrunden og baggrunden. Ondsindede apps kan tvinge sig selv i forgrunden uden din kontrol."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"stoppe kørsel af apps"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Tillader, at en app kan fjerne opgaver og lukke deres apps. Ondsindede apps kan forstyrre adfærden for andre apps."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"aktivere fejlretning af appen"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Tillader, at appen kan slå fejlretning til for en anden app. Ondsindede apps kan bruge dette til at afslutte andre apps."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"skift indstillinger for brugergrænsefladen"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 953897c..7d0ce02 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Ermöglicht der App, Aufgaben in den Vorder- und Hintergrund zu verschieben. Schädliche Apps können so ohne Ihr Zutun eine Anzeige im Vordergrund erzwingen."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"Aktive Apps beenden"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Ermöglicht der App, Aufgaben zu entfernen und die entsprechenden Apps zu beenden. Schädliche Apps können das Verhalten anderer Apps stören."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"Fehlerbeseitigung für App aktivieren"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Ermöglicht der App, die Fehlerbeseitigung für eine andere App zu aktivieren. Schädliche Apps können so andere Apps beenden."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"UI-Einstellungen ändern"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 458517c..49465e8 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Επιτρέπει στην εφαρμογή τη μετακίνηση εργασιών στο προσκήνιο και στο φόντο. Τυχόν κακόβουλες εφαρμογές μπορούν να προωθηθούν στο προσκήνιο χωρίς να μπορείτε να τις ελέγξετε."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"διακοπή εκτέλεσης εφαρμογών"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Επιτρέπει στην εφαρμογή την κατάργηση ενεργειών και την απομάκρυνση των εφαρμογών τους. Τυχόν κακόβουλες εφαρμογές ενδέχεται να διαταράξουν τη λειτουργία άλλων εφαρμογών."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"ενεργοποίηση εντοπισμού σφαλμάτων εφαρμογής"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Επιτρέπει στην εφαρμογή να ενεργοποιήσει τον εντοπισμό σφαλμάτων για μια άλλη εφαρμογή. Τυχόν κακόβουλες εφαρμογές ενδέχεται να χρησιμοποιήσουν αυτήν τη δυνατότητα για τον τερματισμό άλλων εφαρμογών."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"αλλαγή των ρυθμίσεων του UI"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index d48f544..33a3b7a 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Allows the app to move tasks to the foreground and background. Malicious apps may force themselves to the front without your control."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"stop running apps"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Allows the app to remove tasks and kill their apps. Malicious apps may disrupt the behaviour of other apps."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"enable app debugging"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Allows the app to turn on debugging for another app. Malicious apps may use this to kill other apps."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"change your UI settings"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index c66dc8e..41d2a47 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Permite que la aplicación mueva tareas al primero o segundo plano. Las aplicaciones maliciosas pueden forzar su paso al primer plano sin que tú las controles."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"detener las aplicaciones en ejecución"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Permite que la aplicación elimine tareas y cierre sus aplicaciones. Las aplicaciones malintencionadas pueden usar este permiso para interferir en el comportamiento de otras aplicaciones."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"activar depuración de aplicación"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Permite que la aplicación active la depuración de otra aplicación. Las aplicaciones malintencionadas pueden usar este permiso para interrumpir la ejecución de otras aplicaciones."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"cambiar tu configuración de la interfaz de usuario"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 0c526ff4..e9b1ab3 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Permite que la aplicación mueva tareas a segundo o a primer plano. Algunas aplicaciones malintencionadas pueden aparecer en primer plano sin el control del usuario."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"detener aplicaciones en ejecución"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Permite que la aplicación termine tareas y cierre sus aplicaciones. Las aplicaciones malintencionadas pueden usar este permiso para interferir en el comportamiento de otras aplicaciones."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"habilitar depuración de aplicación"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Permite que la aplicación active la depuración de otra aplicación. Las aplicaciones malintencionadas pueden usar este permiso para interrumpir la ejecución de otras aplicaciones."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"cambiar la configuración de la interfaz de usuario"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 5591289..8dfebb6 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Võimaldab rakendusel teisaldada ülesanded esiplaanile ja taustale. Pahatahtlikud rakendused võivad sundida end esiplaanile tulema teie loata."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"käitatud rakenduste peatamine"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Võimaldab rakendusel eemaldada ülesanded ja peatada nende rakendused. Pahatahtlikud rakendused võivad häirida teiste rakenduste käitumist."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"Rakenduse silumise lubamine"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Võimaldab rakendusel lülitada sisse teise rakenduse silumise. Pahatahtlikud rakendused võivad seda kasutada teiste rakenduste peatamiseks."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"muuda UI-seadeid"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 7097e43..a5bf61a 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"به برنامه اجازه میدهد تا کارها را به پیش زمینه و پس زمینه منتقل کند. برنامههای مخرب میتوانند بدون کنترل به اجبار خود را به جلو منتقل کنند."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"متوقف کردن برنامههای در حال اجرا"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"به برنامه اجازه میدهد تا کارها را حذف کند و برنامههای آنها را متوقف کند. برنامههای مخرب میتوانند در اجرای برنامههای دیگر اختلال ایجاد کنند."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"فعال کردن عیبیابی برنامه"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"به برنامه اجازه میدهد تا عیبیابی را برای برنامهای دیگر فعال کند. برنامههای مخرب میتوانند از آن استفاده کنند تا اجرای برنامههای دیگر را متوقف کنند."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"تغییر تنظیمات UI"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 0a60adb..801f815 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Antaa sovelluksen siirtää tehtäviä etualalle ja taustalle. Haitalliset sovellukset voivat pakottaa itsensä etualalle ilman käyttäjän hallintaa."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"käynnissä olevien sovellusten pysäyttäminen"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Antaa sovelluksen poistaa tehtäviä ja lopettaa niiden sovelluksia. Haitalliset sovellukset voivat häiritä muiden sovellusten toimintaa."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"sovellusten vianetsinnän käyttöönotto"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Antaa sovelluksen ottaa vianetsinnän käyttöön toisessa sovelluksessa. Haitalliset ohjelmat voivat lopettaa tällä muita sovelluksia."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"muuta käyttöliittymäsi asetuksia"</string>
@@ -776,7 +780,7 @@
<string name="searchview_description_query" msgid="5911778593125355124">"Hakulauseke"</string>
<string name="searchview_description_clear" msgid="1330281990951833033">"Tyhjennä kysely"</string>
<string name="searchview_description_submit" msgid="2688450133297983542">"Lähetä kysely"</string>
- <string name="searchview_description_voice" msgid="2453203695674994440">"Äänihaku"</string>
+ <string name="searchview_description_voice" msgid="2453203695674994440">"Puhehaku"</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"kuukausi sitten"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Yli kuukausi sitten"</string>
<plurals name="num_seconds_ago">
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index d32f487..2848cd5 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Permet à l\'application de faire passer les tâches de premier plan en arrière-plan. Des applications malveillantes peuvent exploiter cette fonctionnalité pour passer au premier plan sans votre consentement."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"arrêter les applications en cours d\'exécution"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Permet à l\'application de supprimer des tâches et de fermer les applications qui les exécutent. Des applications malveillantes peuvent exploiter cette fonctionnalité pour perturber le comportement des autres applications."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"activer le débogage des applications"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Permet à l\'application d\'activer le débogage d\'une autre application. Des applications malveillantes peuvent exploiter cette fonctionnalité pour en fermer d\'autres."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"Modification des paramètres de l\'IU"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 7a4f706..f56871a3 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"एप्लिकेशन को अग्रभूमि और पृष्ठभूमि में कार्यों को ले जाने देता है. दुर्भावनापूर्ण एप्लिकेशन आपके नियंत्रण के बिना स्वयं को बलपूर्वक आगे कर सकते हैं."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"चलने वाले एप्लिकेशन रोकें"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"किसी एप्लिकेशन को कार्यों को निकालने और उनके एप्लिकेशन समाप्त करने देता है. दुर्भावनापूर्ण एप्लिकेशन अन्य एप्लिकेशन का व्यवहार बाधित कर सकते हैं."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"एप्लिकेशन डीबग करना सक्षम करें"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"एप्लिकेशन को अन्य एप्लिकेशन के लिए डीबग किया जाना चालू करने देता है. दुर्भावनापूर्ण एप्लिकेशन इसका उपयोग अन्य एप्लिकेशन को समाप्त करने के लिए कर सकते हैं."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"अपनी UI सेटिंग बदलें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index e37be22..7c4a9d7a 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Omogućuje aplikaciji da premjesti zadatke u prednji plan ili pozadinu. Zlonamjerne aplikacije mogu na silu doći u prednji plan bez vašeg nadzora."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"zaustavljanje pokrenutih aplikacija"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Omogućuje aplikaciji uklanjanje zadataka i uklanjanje njihovih aplikacija. Zlonamjerne aplikacije mogu poremetiti rad drugih aplikacija."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"omogućavanje rješavanja programskih pogrešaka u aplikaciji"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Omogućuje aplikaciji uključivanje uklanjanja programskih pogrešaka za drugu aplikaciju. Zlonamjerne aplikacije mogu na taj način ukloniti druge aplikacije."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"promjena postavki korisničkog sučelja"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 9b3eb54..e8920bc 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Lehetővé teszi az alkalmazás számára, hogy feladatokat helyezzen át az előtérből a háttérbe és fordítva. A rosszindulatú alkalmazások az előtérbe helyezhetik magukat az Ön engedélye nélkül."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"futó alkalmazások leállítása"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Lehetővé teszi, hogy az alkalmazás feladatokat távolítson el és leállítsa azok alkalmazásait. Rosszindulatú alkalmazások megzavarhatják más alkalmazások viselkedését."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"alkalmazások hibakeresésének bekapcsolása"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Lehetővé teszi az alkalmazás számára, hogy hibakeresést végezzen egy másik alkalmazáson. A rosszindulatú alkalmazások ezzel leállíthatnak más alkalmazásokat."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"a felhasználói felület beállításainak módosítása"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index b61fb42..49b368f 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Mengizinkan apl memindah tugas ke latar depan dan latar belakang. Apl berbahaya dapat memaksa berpindah ke depan tanpa kontrol Anda."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"menghentikan apl yang berjalan"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Memungkinkan apl menghapus tugas dan menutup aplikasinya. Apl berbahaya dapat mengganggu perilaku apl lain."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"mengaktifkan debugging apl"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Mengizinkan apl mengaktifkan debugging untuk apl lain. Apl berbahaya dapat menggunakan cara ini untuk menutup apl lain."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"ubah setelan UI Anda"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index ebf7223..46e90d3 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Consente all\'applicazione di spostare attività in primo piano e in background. Le applicazioni dannose potrebbero forzare la loro impostazione in primo piano senza il tuo controllo."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"interruzione applicazioni in esecuzione"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Consente all\'applicazione di rimuovere le attività e terminare le loro applicazioni. Le applicazioni dannose potrebbero interferire con il comportamento di altre applicazioni."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"attivazione debug delle applicazioni"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Consente all\'applicazione di attivare il debug per un\'altra applicazione. Le applicazioni dannose potrebbero farne uso per terminare altre applicazioni."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"modifica impostazioni UI"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 69d506e..9cde4b3 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"מאפשר ליישום להעביר משימות לחזית ולרקע. יישומים זדוניים עלולים לאלץ את עצמם לעבור לחזית ללא שליטה מצדך."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"עצירת יישומים פעילים"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"הרשאה זו מאפשרת ליישום להסיר משימות ולסגור את היישומים שבהם הן פועלות. יישומים זדוניים עלולים לשבש את פעולתם של יישומים אחרים."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"הפעלה של ניקוי באגים ביישומים"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"הרשאה זו מאפשרת ליישום להפעיל ניקוי באגים עבור יישום אחר. יישומים זדוניים עלולים להשתמש באפשרות זו כדי לסגור יישומים אחרים."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"שנה את הגדרות ממשק המשתמש שלך"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index cb958e4..827644e 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"タスクをフォアグラウンドやバックグラウンドに移動することをアプリに許可します。この許可を悪意のあるアプリに利用されると、悪意のあるアプリが強制的に優先される恐れがあります。"</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"実行中のアプリの停止"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"タスクの削除とアプリの終了をアプリに許可します。この許可を悪意のあるアプリケーションに利用されると、他のアプリの動作が妨害される恐れがあります。"</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"アプリのデバッグの有効化"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"別のアプリをデバッグモードにすることをアプリに許可します。この許可を悪意のあるアプリに利用されると、他のアプリが強制終了される恐れがあります。"</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"UI設定の変更"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 216ac76..14735b0 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"앱이 작업을 포그라운드나 백그라운드로 이동할 수 있도록 허용합니다. 이 경우 악성 앱이 사용자의 조작 없이 앞으로 이동할 수 있습니다."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"실행 중인 앱 중지"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"애플리케이션이 작업을 삭제하거나 다른 애플리케이션을 중지시킬 수 있도록 허용합니다. 이 경우 악성 애플리케이션이 다른 애플리케이션의 동작을 멈추게 할 수 있습니다."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"앱 디버깅 사용"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"애플리케이션이 다른 애플리케이션에 대해 디버깅을 사용할 수 있도록 허용합니다. 이 경우 악성 애플리케이션이 다른 애플리케이션을 중지시킬 수 있습니다."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"UI 설정 변경"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 7f0370f..a83b064 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Leidžiama programai užduotis perkelti į priekinį planą ir į foną. Kenkėjiškos programos gali priverstinai persikelti į priekį be jūsų įsikišimo."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"sustabdyti vykdomas programas"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Leidžiama programai pašalinti užduotis ir panaikinti jų programas. Kenkėjiškos programos gali trikdyti kitų programų veikimą."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"įgalinti programos derinimą"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Leidžiama programai įjungti kitos programos derinimą. Kenkėjiškos programos gali tai naudoti, kad išjungtų kitas programas."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"keisti UI nustatymus"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index a052481..170653a 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Ļauj lietotnei pārvietot uzdevumus priekšplānā un fonā. Ļaunprātīgas lietotnes var tikt izvirzītas priekšplānā bez jūsu vadības."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"apturēt izmantoto lietotņu darbību"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Ļauj lietotnei noņemt uzdevumus un pārtraukt to lietotņu darbību. Ļaunprātīgas lietotnes var traucēt citu lietotņu darbību."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"iespējot lietotnes atkļūdošanu"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Ļauj lietotnei ieslēgt citas lietotnes atkļūdošanu. Ļaunprātīgas lietotnes to var izmantot, lai pārtrauktu citu lietotņu darbību."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"mainīt lietotāja saskarnes iestatījumus"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index f6189f2..498bd83 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Membenarkan apl untuk memindahkan tugasan ke latar depan dan latar belakang. Apl hasad boleh memaksa diri mereka ke hadapan tanpa kawalan anda."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"hentikan apl yang sedang dijalankan"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Membenarkan apl untuk mengalih keluar tugasan dan melupuskan aplnya. Apl hasad boleh mengganggu tingkah laku apl lain."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"dayakan penyahpepijatan apl"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Membenarkan apl untuk menghidupkan penyahpepijatan untuk apl lain. Apl hasad boleh menggunakannya untuk menghapuskan apl lain."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"tukar tetapan UI anda"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index e03b735..084b281 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Lar appen flytte oppgaver til forgrunnen eller bakgrunnen. Ondsinnede apper kan tvinge seg frem til forgrunnen utenfor din kontroll."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"avslutte apper som kjører"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Lar appen fjerne oppgaver og avslutte apper. Ondsinnede apper kan forstyrre atferden til andre apper."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"aktivere feilsøking av app"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Lar appen slå av feilsøking for andre apper. Ondsinnede apper kan bruke dette til å avslutte andre apper."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"endre innstillingene for brukergrensesnitt"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 3a43b8e4..bc23697 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Hiermee kan de app taken naar de voor- en achtergrond verplaatsen. Schadelijke apps kunnen zichzelf op de voorgrond plaatsen zonder dat u hier iets aan kunt doen."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"actieve apps stoppen"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Hiermee kan de app taken verwijderen en apps sluiten. Schadelijke apps kunnen het gedrag van andere apps verstoren."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"foutopsporing in apps inschakelen"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Hiermee kan de app de foutopsporing voor een andere app inschakelen. Schadelijke apps kunnen dit gebruiken om andere apps af te sluiten."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"uw UI-instellingen wijzigen"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index e73f7d6..565fa79 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Pozwala aplikacji na przenoszenie zadań między tłem i pierwszym planem. Złośliwe aplikacje mogą wymusić przeniesienie się na pierwszy plan bez Twojego udziału."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"zatrzymywanie uruchomionych aplikacji"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Umożliwia aplikacji usuwanie zadań i kończenie powiązanych z nimi aplikacji. Złośliwe aplikacje mogą zakłócić działanie innych aplikacji."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"włączenie debugowania aplikacji"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Pozwala aplikacji na włączenie debugowania innej aplikacji. Złośliwe aplikacje mogą to wykorzystać do kończenia pracy innych programów."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"zmienianie ustawień interfejsu użytkownika"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 800013d..28b8463 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Permite à aplicação mover tarefas para primeiro e segundo plano. As aplicações maliciosas podem impor-se em primeiro plano sem o controlo do utilizador."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"parar aplicações em execução"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Permite que a aplicação remova tarefas e elimine as respetivas aplicações. As aplicações maliciosas podem perturbar o comportamento de outras aplicações."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"ativar depuração da aplicação"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Permite que a aplicação ative a depuração para outra aplicação. As aplicações maliciosas podem utilizar isto para eliminar outras aplicações."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"alterar definições da IU"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index c907929..cf6627e 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Permite que o aplicativo mova tarefas para o primeiro plano e para o plano de fundo. Aplicativos maliciosos podem forçar-se para a primeiro plano sem que você tenha controle sobre a ação."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"parar os aplicativos em execução"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Permite que um aplicativo remova tarefas e elimine seus aplicativos. Aplicativos maliciosos podem interferir no comportamento de outros aplicativos."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"ativar depuração do aplicativo"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Permite que o aplicativo ative a depuração para outro aplicativo. Aplicativos maliciosos podem usar esse recurso para cancelar outros aplicativos."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"alterar as suas configurações de UI"</string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index bc8d4fb..a900840 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -278,6 +278,10 @@
<skip />
<!-- no translation found for permdesc_removeTasks (1394714352062635493) -->
<skip />
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<!-- no translation found for permlab_setDebugApp (3022107198686584052) -->
<skip />
<!-- no translation found for permdesc_setDebugApp (4474512416299013256) -->
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index ecee96d..44919ac 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Permite aplicaţiei să mute activităţile în prim-plan şi în fundal. Aplicaţiile rău intenţionate pot să apară forţat în prim-plan, fără ca dvs. să puteţi controla acest lucru."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"oprire aplicaţii care rulează"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Permite aplicaţiei să elimine sarcini şi să închidă aplicaţiile corespunzătoare acestora. Aplicaţiile rău intenţionate pot perturba comportamentul altor aplicaţii."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"activare depanare aplicaţie"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Permite aplicaţiei să activeze depanarea pentru o altă aplicaţie. Aplicaţiile rău intenţionate pot să utilizeze această permisiune pentru a închide alte aplicaţii."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"modificare setări UI"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 7b95291..ace79d3 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Приложение сможет перемещать задачи в режим активного или фонового выполнения. Вредоносные программы смогут переводить себя в активный режим без вашего ведома."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"остановка запущенных приложений"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Приложение сможет удалять задачи и собственные программы. Вредоносное ПО при этом сможет нарушать работу других приложений."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"включение отладки приложений"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Приложение сможет включать отладку для другой программы. Вредоносное ПО сможет таким образом останавливать работу других приложений."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"изменять настройки пользовательского интерфейса"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index aafaa9e..8cb518c 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Umožňuje aplikácii presúvať úlohy do popredia a pozadia. Škodlivé aplikácie sa môžu pretlačiť do popredia bez vášho vedomia."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"zastaviť spustené aplikácie"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Umožňuje aplikácii odstrániť úlohy a ukončiť ich aplikácie. Škodlivé aplikácie môžu narušiť správanie iných aplikácií."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"povoliť ladenie aplikácií"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Umožňuje aplikácii zapnúť ladenie inej aplikácie. Škodlivé aplikácie môžu pomocou tohto nastavenia ukončiť iné aplikácie."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"zmeny vašich nastavení používateľského rozhrania"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index aa98c80..e7a6c07 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Programu omogoča premikanje opravil v ospredje in ozadje. Zlonamerni programi se lahko brez vašega nadzora vsilijo v ospredje."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"ustavitev programov, ki se izvajajo"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Programu omogoča odstranjevanje opravil in zapiranje njihovih programov. Zlonamerni programi lahko motijo delovanje drugih programov."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"omogočanje iskanja in odpravljanja napak v programu"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Programu omogoča vklop funkcije za odpravljanje napak za drug program. Zlonamerni programi lahko to uporabijo za zapiranje drugih programov."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"spreminjanje nastavitev UV"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 7ba8503..2374f59 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Дозвољава апликацији да премешта задатке у први план и у позадину. Злонамерне апликације могу на тај начин да принудно пређу у први план без ваше контроле."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"заустављање покренутих апликација"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Дозвољава апликацији да уклања задатке и уништава њихове апликације. Злонамерне апликације могу да поремете понашање других апликација."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"омогућавање отклањања грешака у апликацији"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Дозвољава апликацији да укључи уклањање грешака за другу апликацију. Злонамерне апликације могу то да искористе за онемогућавање других апликација."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"промена подешавања корисничког интерфејса"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 4d3cea5..26e1ea5 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Tillåter att appen flyttar uppgifter till förgrunden eller bakgrunden. Skadliga appar kan tvinga sig till förgrunden utan att du kan styra det."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"avsluta appar som körs"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Tillåter att appen tar bort uppgifter och avslutar appar. Skadliga appar kan störa funktionen i andra appar."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"aktivera felsökning av appar"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Tillåter att appen aktiverar felsökning för en annan app. Skadliga appar kan använda detta för att avsluta andra appar."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"ändra dina gränssnittsinställningar"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index a9a8679..22ce660 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Inaruhusu programu kusongesha kazi kwenye mandhari-mbele na mandhari-nyuma. Programu hasidi zinaweza kujilazimisha mbele bila udhibiti wako."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"Komesha programu zinazoendeshwa"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Huruhusu programu kuondoa majukumu na kuua programu zao. Programu hasidi zinaweza kutatiza tabia ya programu zingine."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"wezesha utatuaji wa programu"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Huruhusu programu kuwasha kueua cha programu nyingine. Programu hasidi huenda zikatumia hii ili kuua programu nyingine."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"badilisha mipangilio yako ya onyesho"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 6a8431c..0ff883d 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"อนุญาตให้แอปพลิเคชันย้ายงานไปยังส่วนหน้าและพื้นหลัง แอปพลิเคชันที่เป็นอันตรายอาจบังคับตัวเองให้ไปที่ส่วนหน้าโดยไม่มีการควบคุมจากคุณ"</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"หยุดแอปพลิเคชันที่ทำงานอยู่"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"อนุญาตให้แอปพลิเคชันลบงานออกและยุติแอปพลิเคชันต่างๆ ของงานนั้น แอปพลิเคชันที่เป็นอันตรายอาจทำให้แอปพลิเคชันอื่นๆ ทำงานได้ไม่ถูกต้อง"</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"เปิดใช้งานการแก้ไขบกพร่องของแอปพลิเคชัน"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"อนุญาตให้แอปพลิเคชันเปิดการแก้ไขข้อบกพร่องสำหรับแอปพลิเคชันอื่น แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ยุติการทำงานของแอปพลิเคชันอื่นๆ ได้"</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"เปลี่ยนการตั้งค่า UI ของคุณ"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 04635c8..889b3a9 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Pinapayagan ang app na ilipat ang mga gawain sa foreground at background. Maaaring puwersahin ng nakakahamak na apps ang mga sarili nito sa harapan nang wala ang iyong pagkontrol."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"ihinto ang pagpapatakbo ng apps"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Pinapayagan ang app na mag-alis ng mga gawain at i-off ang apps nito. Maaaring maantala ng nakakahamak na apps ang pagkilos ng iba pang apps."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"paganahin ang pag-debug ng app"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Pinapayagan ang app na i-on ang pag-debug para sa isa pang app. Maaari itong gamitin ng nakakahamak na apps upang i-off ang iba pang apps."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"baguhin ang iyong mga setting ng UI"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index bfe9c0a..07e4ec9 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Uygulamaya, görevleri ön plana ve arka plana taşıma izni verir. Kötü amaçlı uygulamalar kendilerini sizin denetiminiz dışında ön plana taşıyabilir."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"çalışan uygulamaları durdur"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Uygulamaya, görevleri kaldırma ve bunlara ait uygulamaları kapatma izni verir. Kötü amaçlı uygulamalar diğer uygulamaların çalışmasını bozabilir."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"uygulama hata ayıklamayı etkinleştir"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Uygulamaya, başka bir uygulama için hata ayıklamayı açma izni verir. Kötü amaçlı uygulamalar diğer uygulamaları kaldırmak için bunu kullanabilir."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"kullanıcı arayüzü ayarlarınızı değiştirin"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 6708893..ac2ea3c 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Дозволяє програмі переміщувати завдання в активні чи фонові вікна. Шкідливі програми можуть примусово ставати активними без вашого відома."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"зупиняти запущені програми"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Дозволяє програмі видаляти завдання та примусово припиняти роботу відповідних програм. Шкідливі програми можуть переривати роботу інших програм."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"вмикати налагодження програми"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Дозволяє програмі вмикати налагодження для іншої програми. Шкідливі програми можуть використовувати це для примусового припинення роботи інших програм."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"змін. налашт. інтерф. кор."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 6da402ce..9f2fe0c 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Cho phép ứng dụng di chuyển công việc sang nền trước và nền sau. Ứng dụng độc hại có thể tự hiển thị ở nền trước mà không chịu sự kiểm soát của bạn."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"dừng các ứng dụng đang chạy"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Cho phép ứng dụng xóa công việc và loại bỏ các ứng dụng của chúng. Ứng dụng độc hại có thể làm gián đoạn hoạt động của các ứng dụng khác."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"bật gỡ lỗi ứng dụng"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Cho phép ứng dụng bật gỡ lỗi cho một ứng dụng khác. Ứng dụng độc hại có thể sử dụng quyền này để loại bỏ những ứng dụng khác."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"thay đổi cài đặt giao diện người dùng của bạn"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 6c40202..89f5ad0 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"允许应用程序将任务移动到前台和后台。恶意应用程序可能会不受您的控制,强行让自己处于前台。"</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"停止正在运行的应用程序"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"允许该应用程序删除任务并终止这些任务的应用程序。恶意应用程序可以籍此影响其他应用程序的行为。"</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"启用应用程序调试"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"允许该应用程序对其他应用程序启用调试。恶意应用程序可以籍此终止其他的应用程序。"</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"更改用户界面设置"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 131c2f7..ededae8 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"允許應用程式將工作移至前景或背景。請注意,惡意應用程式可能利用此功能自行移動至前景。"</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"停止執行中的應用程式"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"允許應用程式移除工作並終止執行工作的應用程式。請注意,惡意應用程式可能利用此功能干擾其他應用程式的行為。"</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"啟用應用程式偵錯"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"允許應用程式為其他程式開啟偵錯功能。提醒您,惡意應用程式可能會利用這個功能終止其他應用程式。"</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"變更介面設定"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 56af9aa..3ee95be 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Ivumela insiza ukuthi ihambise izenzo ziye ngaphambili kanye nasemumva. Izinsiza ezinobungozi zingaziphoqelela ukuth iziye phambili ngaphandle kokulawula kwakho."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"misa izinsiza ezisebenzayo"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Vumela ukuthi insiza isuse okumele kwenziwe ibulale nezinsiza zakho. Izinsiza eziwubungozi zingaphazamisa ukusebenza kwezinye izinsiza."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"vumela insiza ilungise inkinga"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Ivumela insiza ukuthi ivule uhlelo lokulungisa lwenye insiza. Izinsiza ezinobungozi zingasebenzisa lokhu ukubulala ezinye izinsiza."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"shintsha izilungiselelo zakho ze-UI"</string>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index dbd49fb..92c59ab 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1235,6 +1235,10 @@
when the user remove a task rooted in an activity owned by
the application. The default is false. -->
<attr name="stopWithTask" format="boolean" />
+ <!-- If set to true, this service will run under a special process
+ that is isolated from the rest of the system. The only communication
+ with it is through the Service API (binding and starting). -->
+ <attr name="isolatedProcess" format="boolean" />
</declare-styleable>
<!-- The <code>receiver</code> tag declares an
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 0511b75..3a7225e 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -61,6 +61,25 @@
As of Honeycomb, blurring is not supported anymore. -->
<bool name="config_sf_slowBlur">true</bool>
+ <!-- Flag indicating that the media framework should allow changing
+ master volume stream and nothing else . -->
+ <bool name="config_useMasterVolume">false</bool>
+
+ <!-- Array of integer pairs controlling the rate at which the master volume changes
+ in response to volume up and down key events.
+ The first integer of each pair is compared against the current master volume
+ (in range 0 to 100).
+ The last pair with first integer <= the current volume is chosen,
+ and the second integer of the pair indicates the amount to increase the master volume
+ when volume up is pressed. -->
+ <integer-array name="config_masterVolumeRamp">
+ <item>0</item> <item>5</item> <!-- default: always increase volume by 5% -->
+ </integer-array>
+
+ <!-- Flag indicating whether the AUDIO_BECOMING_NOISY notification should
+ be sent during an change to the audio output device. -->
+ <bool name="config_sendAudioBecomingNoisy">true</bool>
+
<!-- The duration (in milliseconds) of a short animation. -->
<integer name="config_shortAnimTime">200</integer>
@@ -364,6 +383,12 @@
<string-array name="config_usbHostBlacklist" translatable="false">
</string-array>
+ <!-- List of paths to serial ports that are available to the serial manager.
+ for example, /dev/ttyUSB0
+ -->
+ <string-array translatable="false" name="config_serialPorts">
+ </string-array>
+
<!-- Vibrator pattern for feedback about a long screen/key press -->
<integer-array name="config_longPressVibePattern">
<item>0</item>
@@ -535,6 +560,9 @@
specified -->
<string name="default_wallpaper_component" translatable="false">@null</string>
+ <!-- True if WallpaperService is enabled -->
+ <bool name="config_enableWallpaperService">true</bool>
+
<!-- Component name of the service providing network location support. -->
<string name="config_networkLocationProvider" translatable="false">@null</string>
@@ -760,4 +788,10 @@
movement threshold where scrolling should begin. -->
<dimen name="config_viewConfigurationTouchSlop">8dp</dimen>
+ <!-- Array of OEM specific USB mode override config.
+ OEM can override a certain USB mode depending on ro.bootmode.
+ Specify an array of below items to set override rule.
+ [bootmode]:[original USB mode]:[USB mode used]-->
+ <integer-array translatable="false" name="config_oemUsbModeOverride">
+ </integer-array>
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index e3c2bd8..e84cb5c 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -234,6 +234,9 @@
<java-symbol type="bool" name="preferences_prefer_dual_pane" />
<java-symbol type="bool" name="skip_restoring_network_selection" />
<java-symbol type="bool" name="split_action_bar_is_narrow" />
+ <java-symbol type="bool" name="config_useMasterVolume" />
+ <java-symbol type="bool" name="config_enableWallpaperService" />
+ <java-symbol type="bool" name="config_sendAudioBecomingNoisy" />
<java-symbol type="integer" name="config_cursorWindowSize" />
<java-symbol type="integer" name="config_longPressOnPowerBehavior" />
@@ -859,6 +862,7 @@
<java-symbol type="array" name="preloaded_drawables" />
<java-symbol type="array" name="special_locale_codes" />
<java-symbol type="array" name="special_locale_names" />
+ <java-symbol type="array" name="config_masterVolumeRamp" />
<java-symbol type="drawable" name="default_wallpaper" />
<java-symbol type="drawable" name="ic_suggestions_add" />
@@ -1288,7 +1292,9 @@
<java-symbol type="array" name="config_tether_usb_regexs" />
<java-symbol type="array" name="config_tether_wifi_regexs" />
<java-symbol type="array" name="config_usbHostBlacklist" />
+ <java-symbol type="array" name="config_serialPorts" />
<java-symbol type="array" name="radioAttributes" />
+ <java-symbol type="array" name="config_oemUsbModeOverride" />
<java-symbol type="bool" name="config_animateScreenLights" />
<java-symbol type="bool" name="config_automatic_brightness_available" />
<java-symbol type="bool" name="config_sf_limitedAlpha" />
@@ -3482,4 +3488,10 @@
<public type="color" name="holo_orange_dark" id="0x01060019" />
<public type="color" name="holo_purple" id="0x0106001a" />
<public type="color" name="holo_blue_bright" id="0x0106001b" />
+
+<!-- ===============================================================
+ Resources added in version 16 of the platform (Jelly Bean)
+ =============================================================== -->
+ <public type="attr" name="isolatedProcess" id="0x010103a7" />
+
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index dc45c408..4995d2c 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -532,6 +532,13 @@
tasks and kill their apps. Malicious apps may disrupt
the behavior of other apps.</string>
+ <!-- Title of an application permission, allowing control of app screen compatibility mode -->
+ <string name="permlab_setScreenCompatibility">set screen compatibility</string>
+ <!-- Description of an application permission, allowing control of app screen compatibility mode -->
+ <string name="permdesc_setScreenCompatibility">Allows the app to control the
+ screen compatibility mode of other applications. Malicious applications may
+ break the behavior of other applications.</string>
+
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_setDebugApp">enable app debugging</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -2236,6 +2243,11 @@
<string name="permdesc_bindPackageVerifier">Allows the holder to make requests of
package verifiers. Should never be needed for normal apps.</string>
+ <!-- Title of an application permission which allows the application to access serial ports via the SerialManager. [CHAR LIMIT=40] -->
+ <string name="permlab_serialPort">access serial ports</string>
+ <!-- Description of an application permission which allows the application access serial ports via the SerialManager. [CHAR LIMIT=NONE] -->
+ <string name="permdesc_serialPort">Allows the holder to access serial ports using the SerialManager API.</string>
+
<!-- If the user enters a password in a form on a website, a dialog will come up asking if they want to save the password. Text in the save password dialog, asking if the browser should remember a password. -->
<string name="save_password_message">Do you want the browser to remember this password?</string>
<!-- If the user enters a password in a form on a website, a dialog will come up asking if they want to save the password. Button in the save password dialog, saying not to remember this password. -->
diff --git a/data/etc/android.hardware.bluetooth.xml b/data/etc/android.hardware.bluetooth.xml
new file mode 100644
index 0000000..4aa1744
--- /dev/null
+++ b/data/etc/android.hardware.bluetooth.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+<!-- Adds the feature indicating support for the Bluetooth API -->
+<permissions>
+ <feature name="android.hardware.bluetooth" />
+</permissions>
diff --git a/docs/html/guide/developing/devices/managing-avds.jd b/docs/html/guide/developing/devices/managing-avds.jd
index 1817ce7..e70a0bb 100644
--- a/docs/html/guide/developing/devices/managing-avds.jd
+++ b/docs/html/guide/developing/devices/managing-avds.jd
@@ -233,13 +233,5 @@
<td>hw.lcd.density</td>
</tr>
-
- <tr>
- <td>Trackball support</td>
-
- <td>Whether there is a trackball present.</td>
-
- <td>hw.trackBall</td>
- </tr>
</table>
diff --git a/docs/html/guide/developing/projects/index.jd b/docs/html/guide/developing/projects/index.jd
index ac8a1a5..63e67cd 100644
--- a/docs/html/guide/developing/projects/index.jd
+++ b/docs/html/guide/developing/projects/index.jd
@@ -179,8 +179,9 @@
<dd>Customizable computer-specific properties for the build system. If you use Ant to build
the project, this contains the path to the SDK installation. Because the content of the file
- is specific to the local installation of the SDK, maintained it in a source
- revision control system. If you use Eclipse, this file is not used.</dd>
+ is specific to the local installation of the SDK, the <code>local.properties</code> should not
+be maintained in a source revision control system. If you use Eclipse, this file is not
+used.</dd>
<dt><code>ant.properties</code></dt>
diff --git a/docs/html/guide/topics/fundamentals.jd b/docs/html/guide/topics/fundamentals.jd
index 661f5cb..d1a3786 100644
--- a/docs/html/guide/topics/fundamentals.jd
+++ b/docs/html/guide/topics/fundamentals.jd
@@ -243,7 +243,7 @@
android.content.ContentResolver} object. This leaves a layer of abstraction between the content
provider and the component requesting information (for security).</p>
-<p>There are separate methods for activiting each type of component:</p>
+<p>There are separate methods for activating each type of component:</p>
<ul>
<li>You can start an activity (or give it something new to do) by
passing an {@link android.content.Intent} to {@link android.content.Context#startActivity
@@ -400,7 +400,7 @@
requirements in your manifest file. That way, devices that do <em>not</em> have a camera and have an
Android version <em>lower</em> than 2.1 cannot install your application from Android Market.</p>
-<p>However, you can also declare that your applicaiton uses the camera, but does not
+<p>However, you can also declare that your application uses the camera, but does not
<em>require</em> it. In that case, your application must perform a check at runtime to determine
if the device has a camera and disable any features that use the camera if one is not available.</p>
diff --git a/docs/html/guide/topics/fundamentals/loaders.jd b/docs/html/guide/topics/fundamentals/loaders.jd
index 3aad204..ddd513b 100644
--- a/docs/html/guide/topics/fundamentals/loaders.jd
+++ b/docs/html/guide/topics/fundamentals/loaders.jd
@@ -491,7 +491,7 @@
LoaderCursor</a> — A complete version of the
snippet shown above.</li>
<li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderThrottle.html"> LoaderThrottle</a> — An example of how to use throttling to
-reduce the number of queries a content provider does then its data changes.</li>
+reduce the number of queries a content provider does when its data changes.</li>
</ul>
<p>For information on downloading and installing the SDK samples, see <a
diff --git a/docs/html/guide/topics/manifest/activity-element.jd b/docs/html/guide/topics/manifest/activity-element.jd
index 4d9603f..f44901b 100644
--- a/docs/html/guide/topics/manifest/activity-element.jd
+++ b/docs/html/guide/topics/manifest/activity-element.jd
@@ -272,10 +272,11 @@
</p></dd>
<dt><a name="exclude"></a>{@code android:excludeFromRecents}</dt>
-<dd>Whether or not the activity should be excluded from the list of recently
-launched activities that can be displayed to users — "{@code true}" if
-it should be excluded, and "{@code false}" if it should be included.
-The default value is "{@code false}".
+<dd>Whether or not the task initiated by this activity should be excluded from the list of recently
+used applications ("recent apps"). That is, when this activity is the root activity of a new task,
+this attribute determines whether the task should not appear in the list of recent apps. "{@code
+true}" if the task should be <em>excluded</em> from the list; "{@code false}" if it should be
+<em>included</em>. The default value is "{@code false}".
</p></dd>
<dt><a name="exported"></a>{@code android:exported}</dt>
diff --git a/docs/html/guide/topics/resources/drawable-resource.jd b/docs/html/guide/topics/resources/drawable-resource.jd
index 80de9f9..a34ed6c 100644
--- a/docs/html/guide/topics/resources/drawable-resource.jd
+++ b/docs/html/guide/topics/resources/drawable-resource.jd
@@ -1248,7 +1248,6 @@
android:drawable="@drawable/android"
android:clipOrientation="horizontal"
android:gravity="left" />
-</clip>
</pre>
<p>The following layout XML applies the clip drawable to a View:</p>
<pre>
diff --git a/docs/html/guide/topics/resources/more-resources.jd b/docs/html/guide/topics/resources/more-resources.jd
index 972eab9..d37b9f8 100644
--- a/docs/html/guide/topics/resources/more-resources.jd
+++ b/docs/html/guide/topics/resources/more-resources.jd
@@ -216,27 +216,29 @@
For example: 10px, 2in, 5sp. The following units of measure are supported by Android:</p>
<dl>
<dt>{@code dp}</dt>
- <dd>Density-independent Pixels - an abstract unit that is based on the physical density of the
-screen. These units are relative to a 160 dpi (dots per inch) screen, so <em>{@code 160dp} is
-always one inch</em> regardless of the screen density. The ratio of dp-to-pixel will change with the
-screen density, but not necessarily in direct proportion. You should use these units when specifying
-view dimensions in your layout, so the UI properly scales to render at the same actual size on
-different screens. (The compiler accepts both "dip" and "dp", though "dp" is more consistent with
-"sp".)</dd>
+ <dd>Density-independent Pixels - An abstract unit that is based on the physical density of the
+screen. These units are relative to a 160 dpi (dots per inch) screen, on which 1dp is roughly equal
+to 1px. When running on a higher density screen, the number of pixels used to draw 1dp is scaled up
+by a factor appropriate for the screen's dpi. Likewise, when on a lower density screen, the number
+of pixels used for 1dp is scaled down. The ratio of dp-to-pixel will change with the screen density,
+but not necessarily in direct proportion. Using dp units (instead of px units) is a simple solution
+to making the view dimensions in your layout resize properly for different screen densities. In
+other words, it provides consistency for the real-world sizes of your UI elements across different
+devices.</dd>
<dt>{@code sp}</dt>
- <dd>Scale-independent Pixels - this is like the dp unit, but it is also scaled by the user's font
+ <dd>Scale-independent Pixels - This is like the dp unit, but it is also scaled by the user's font
size preference. It is recommend you use this unit when specifying font sizes, so they will be adjusted
for both the screen density and the user's preference.</dd>
<dt>{@code pt}</dt>
<dd>Points - 1/72 of an inch based on the physical size of the screen.</dd>
<dt>{@code px}</dt>
- <dd>Pixels - corresponds to actual pixels on the screen. This unit of measure is not recommended because
+ <dd>Pixels - Corresponds to actual pixels on the screen. This unit of measure is not recommended because
the actual representation can vary across devices; each devices may have a different number of pixels
per inch and may have more or fewer total pixels available on the screen.</dd>
<dt>{@code mm}</dt>
- <dd>Millimeters - based on the physical size of the screen.</dd>
+ <dd>Millimeters - Based on the physical size of the screen.</dd>
<dt>{@code in}</dt>
- <dd>Inches - based on the physical size of the screen.</dd>
+ <dd>Inches - Based on the physical size of the screen.</dd>
</dl>
<p class="note"><strong>Note:</strong> A dimension is a simple resource that is referenced
diff --git a/docs/html/guide/topics/ui/menus.jd b/docs/html/guide/topics/ui/menus.jd
index a2313b3..d51a378 100644
--- a/docs/html/guide/topics/ui/menus.jd
+++ b/docs/html/guide/topics/ui/menus.jd
@@ -17,7 +17,7 @@
<li><a href="#context-menu">Creating Contextual Menus</a>
<ol>
<li><a href="#FloatingContextMenu">Creating a floating context menu</a></li>
- <li><a href="#CAB">Using the contextual action bar</a></li>
+ <li><a href="#CAB">Using the contextual action mode</a></li>
</ol>
</li>
<li><a href="#PopupMenu">Creating a Popup Menu</a>
diff --git a/docs/html/resources/articles/faster-screen-orientation-change.jd b/docs/html/resources/articles/faster-screen-orientation-change.jd
index 52531bb..e7b73bf 100644
--- a/docs/html/resources/articles/faster-screen-orientation-change.jd
+++ b/docs/html/resources/articles/faster-screen-orientation-change.jd
@@ -58,7 +58,7 @@
<p>When your application displays a lot of data, or data that is expensive to fetch,
the automatic destruction/creation of the activities can be lead to a
-painful user experience. Take the example of <a href="http://code.google.com/p/apps-for-android/source/browse/trunk/Photostream/">Photostream</a>,
+painful user experience. Take the example of <a href="http://code.google.com/p/apps-for-android/source/browse/#git%2FPhotostream%2Fsrc%2Fcom%2Fgoogle%2Fandroid%2Fphotostream">Photostream</a>,
a simple Flickr browsing application. After you launch the application and choose a Flickr account, the
application downloads a set of 6 photos (on a T-Mobile G1) from the
Flickr servers and displays them on screen. To improve the user
@@ -80,9 +80,9 @@
<p>The Activity class has a special method called
{@link android.app.Activity#onRetainNonConfigurationInstance()}. This method
-can be used to pass an arbitrary object <em>your future self</em> and Android
+can be used to pass an arbitrary object to <em>your future self</em> and Android
is smart enough to call this method only when needed. In the case of Photostream,
-the application <a href="http://code.google.com/p/apps-for-android/source/browse/trunk/Photostream/src/com/google/android/photostream/PhotostreamActivity.java#226">used this method</a>
+the application used this method
to pass the downloaded images to the future activity on orientation change.
The implementation can be summarized like so:</p>
@@ -96,7 +96,7 @@
<p>In the new activity, in <code>onCreate()</code>, all you have to do to
get your object back is to call {@link android.app.Activity#getLastNonConfigurationInstance()}.
-In Photostream, <a href="http://code.google.com/p/apps-for-android/source/browse/trunk/Photostream/src/com/google/android/photostream/PhotostreamActivity.java#251">this method is invoked</a>
+In Photostream, this method is invoked
and if the returned value is not null, the grid is loaded with the list of
photos from the previous activity:</p>
@@ -128,3 +128,6 @@
<code>onRetainNonConfigurationChange()</code> should be used only to retain
data that is expensive to load. Otherwise, keep it simple and let Android
do everything.</p>
+
+<p>Also read the guide to <a href="{@docRoot}guide/topics/resources/runtime-changes.html">Handling Runtime
+Changes</a>.</p>
diff --git a/docs/html/resources/faq/troubleshooting.jd b/docs/html/resources/faq/troubleshooting.jd
index 05a7ddab..f19f5ec 100644
--- a/docs/html/resources/faq/troubleshooting.jd
+++ b/docs/html/resources/faq/troubleshooting.jd
@@ -222,8 +222,8 @@
<ol>
<li>In a terminal, change to the tools directory of the SDK.</li>
- <li>If no emulator instance is running, start an emulator using using the command <code>emulator &</code>.</li>
- <li>Uninstall the preinstalled app using the command <code>adb uninstall com.android.samples</code>.</li>
+ <li>If no emulator instance is running, start an emulator using using the command <code>emulator</code>.</li>
+ <li>Uninstall the preinstalled app using the command <code>adb uninstall com.example.android.apis</code>.</li>
<li>Reinstall the app using the command <code>adb install <path to the ApiDemos.apk></code>. If you are
working in Eclipse/ADT, you can just compile and run the app in the normal way. </li>
</ol>
diff --git a/docs/html/resources/tutorials/notepad/notepad-ex2.jd b/docs/html/resources/tutorials/notepad/notepad-ex2.jd
index 7e3288f1..ed06778 100644
--- a/docs/html/resources/tutorials/notepad/notepad-ex2.jd
+++ b/docs/html/resources/tutorials/notepad/notepad-ex2.jd
@@ -87,8 +87,7 @@
menu callback used for the options menu. Here, we add just one line, which will add a menu item
to delete a note. Call <code>menu.add()</code> like so:
<pre>
-public void onCreateContextMenu(Menu menu, View v,
- ContextMenu.ContextMenuInfo menuInfo) {
+public void onCreateContextMenu(Menu menu, View v, ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
menu.add(0, DELETE_ID, 0, R.string.menu_delete);
}</pre>
diff --git a/docs/html/resources/tutorials/opengl/opengl-es10.jd b/docs/html/resources/tutorials/opengl/opengl-es10.jd
index 3570766..2b44620 100644
--- a/docs/html/resources/tutorials/opengl/opengl-es10.jd
+++ b/docs/html/resources/tutorials/opengl/opengl-es10.jd
@@ -58,7 +58,7 @@
needs. For more information, see
<a href="{@docRoot}guide/topics/graphics/opengl.html#choosing-version">Choosing an OpenGL API
Version</a>. If you would prefer to use OpenGL ES 2.0, see the <a
-href="{@docRoot}resources/tutorials/opengl/opengl-es20.jd">OpenGL ES 2.0 tutorial</a>.</p>
+href="{@docRoot}resources/tutorials/opengl/opengl-es20.html">OpenGL ES 2.0 tutorial</a>.</p>
<p>Before you start, you should understand how to create a basic Android application. If you do not
know how to create an app, follow the <a href="{@docRoot}resources/tutorials/hello-world.html">Hello
diff --git a/docs/html/resources/tutorials/opengl/opengl-es20.jd b/docs/html/resources/tutorials/opengl/opengl-es20.jd
index 889dd50..dd23dbf 100644
--- a/docs/html/resources/tutorials/opengl/opengl-es20.jd
+++ b/docs/html/resources/tutorials/opengl/opengl-es20.jd
@@ -57,7 +57,7 @@
needs. For more information, see
<a href="{@docRoot}guide/topics/graphics/opengl.html#choosing-version">Choosing an OpenGL API
Version</a>. If you would prefer to use OpenGL ES 1.0, see the <a
-href="{@docRoot}resources/tutorials/opengl/opengl-es10.jd">OpenGL ES 1.0 tutorial</a>.</p>
+href="{@docRoot}resources/tutorials/opengl/opengl-es10.html">OpenGL ES 1.0 tutorial</a>.</p>
<p>Before you start, you should understand how to create a basic Android application. If you do not
know how to create an app, follow the <a href="{@docRoot}resources/tutorials/hello-world.html">Hello
diff --git a/docs/html/resources/tutorials/views/hello-mapview.jd b/docs/html/resources/tutorials/views/hello-mapview.jd
index 836d22c..ac5e826 100644
--- a/docs/html/resources/tutorials/views/hello-mapview.jd
+++ b/docs/html/resources/tutorials/views/hello-mapview.jd
@@ -255,7 +255,7 @@
<pre>
List<Overlay> mapOverlays = mapView.getOverlays();
Drawable drawable = this.getResources().getDrawable(R.drawable.androidmarker);
-HelloItemizedOverlay itemizedoverlay = new HelloItemizedOverlay(drawable);</pre>
+HelloItemizedOverlay itemizedoverlay = new HelloItemizedOverlay(drawable, this);</pre>
<p>All overlay elements on a map are held by the {@code MapView}, so when you want to add some,
you have to get a list from the <code>getOverlays()</code> method. Then instantiate the {@link
diff --git a/docs/html/sdk/download.jd b/docs/html/sdk/download.jd
index 44fe5e4..af25609 100644
--- a/docs/html/sdk/download.jd
+++ b/docs/html/sdk/download.jd
@@ -52,7 +52,7 @@
<script language="javascript">
var loc = window.location.href;
if (loc.indexOf('?v=') != -1) {
- var filename = loc.substring(loc.indexOf('=')+1,loc.length);
+ var filename = loc.substring(loc.indexOf('=')+1,loc.length).replace(/</g,"<").replace(/>/g,">");
document.write("File: " + filename);
}
</script>
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index 8d17561..bff2a76 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -518,15 +518,16 @@
byte[] np = bm.getNinePatchChunk();
final boolean isNinePatch = np != null && NinePatch.isNinePatchChunk(np);
if (opts.inScaled || isNinePatch) {
- float scale = targetDensity / (float)density;
- // TODO: This is very inefficient and should be done in native by Skia
- final Bitmap oldBitmap = bm;
- bm = Bitmap.createScaledBitmap(oldBitmap, (int) (bm.getWidth() * scale + 0.5f),
- (int) (bm.getHeight() * scale + 0.5f), true);
- oldBitmap.recycle();
+ float scale = targetDensity / (float) density;
+ if (scale != 1.0f) {
+ final Bitmap oldBitmap = bm;
+ bm = Bitmap.createScaledBitmap(oldBitmap, (int) (bm.getWidth() * scale + 0.5f),
+ (int) (bm.getHeight() * scale + 0.5f), true);
+ if (bm != oldBitmap) oldBitmap.recycle();
+ }
if (isNinePatch) {
- np = nativeScaleNinePatch(np, scale, outPadding);
+ if (scale != 1.0f) np = nativeScaleNinePatch(np, scale, outPadding);
bm.setNinePatchChunk(np);
}
bm.setDensity(targetDensity);
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index 11c2427..509b972 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -22,6 +22,7 @@
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.graphics.SurfaceTexture;
import android.util.Log;
import android.util.TypedValue;
@@ -78,6 +79,8 @@
boolean mConstrainedFace;
boolean mConstrainedY;
boolean mConstrainedZ;
+ boolean mReadAllowed = true;
+ boolean mWriteAllowed = true;
int mSelectedY;
int mSelectedZ;
int mSelectedLOD;
@@ -127,6 +130,32 @@
*/
public static final int USAGE_GRAPHICS_RENDER_TARGET = 0x0010;
+ /**
+ * USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT The allcation will be
+ * used with a SurfaceTexture object. This usage will cause the
+ * allocation to be created read only.
+ *
+ * @hide
+ */
+ public static final int USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE = 0x0020;
+
+ /**
+ * USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT The allcation will be
+ * used with a SurfaceTexture object. This usage will cause the
+ * allocation to be created read only.
+ *
+ * @hide
+ */
+
+ public static final int USAGE_IO_INPUT = 0x0040;
+ /**
+ * USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT The allcation will be
+ * used with a SurfaceTexture object. This usage will cause the
+ * allocation to be created read only.
+ *
+ * @hide
+ */
+ public static final int USAGE_IO_OUTPUT = 0x0080;
/**
* Controls mipmap behavior when using the bitmap creation and
@@ -187,10 +216,26 @@
USAGE_GRAPHICS_TEXTURE |
USAGE_GRAPHICS_VERTEX |
USAGE_GRAPHICS_CONSTANTS |
- USAGE_GRAPHICS_RENDER_TARGET)) != 0) {
+ USAGE_GRAPHICS_RENDER_TARGET |
+ USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE |
+ USAGE_IO_INPUT |
+ USAGE_IO_OUTPUT)) != 0) {
throw new RSIllegalArgumentException("Unknown usage specified.");
}
+
+ if ((usage & (USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE | USAGE_IO_INPUT)) != 0) {
+ mWriteAllowed = false;
+
+ if ((usage & ~(USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE |
+ USAGE_IO_INPUT |
+ USAGE_GRAPHICS_TEXTURE |
+ USAGE_SCRIPT)) != 0) {
+ throw new RSIllegalArgumentException("Invalid usage combination.");
+ }
+ }
+
mType = t;
+ mUsage = usage;
if (t != null) {
updateCacheInfo(t);
@@ -1006,6 +1051,23 @@
}
/**
+ *
+ *
+ * @hide
+ *
+ */
+ public SurfaceTexture getSurfaceTexture() {
+ if ((mUsage & USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE) == 0) {
+ throw new RSInvalidStateException("Allocation is not a surface texture.");
+ }
+
+ int id = mRS.nAllocationGetSurfaceTextureID(getID());
+ return new SurfaceTexture(id);
+
+ }
+
+
+ /**
* Creates a non-mipmapped renderscript allocation to use as a
* graphics texture
*
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index bfe412c..3f3033b 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -269,6 +269,12 @@
validate();
rsnAllocationSyncAll(mContext, alloc, src);
}
+ native int rsnAllocationGetSurfaceTextureID(int con, int alloc);
+ synchronized int nAllocationGetSurfaceTextureID(int alloc) {
+ validate();
+ return rsnAllocationGetSurfaceTextureID(mContext, alloc);
+ }
+
native void rsnAllocationGenerateMipmaps(int con, int alloc);
synchronized void nAllocationGenerateMipmaps(int alloc) {
validate();
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index 9622bd2..a9f0f1f 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -443,6 +443,13 @@
rsAllocationSyncAll(con, (RsAllocation)a, (RsAllocationUsageType)bits);
}
+static jint
+nAllocationGetSurfaceTextureID(JNIEnv *_env, jobject _this, RsContext con, jint a)
+{
+ LOG_API("nAllocationGetSurfaceTextureID, con(%p), a(%p)", con, (RsAllocation)a);
+ return rsAllocationGetSurfaceTextureID(con, (RsAllocation)a);
+}
+
static void
nAllocationGenerateMipmaps(JNIEnv *_env, jobject _this, RsContext con, jint alloc)
{
@@ -1258,6 +1265,7 @@
{"rsnAllocationCopyToBitmap", "(IILandroid/graphics/Bitmap;)V", (void*)nAllocationCopyToBitmap },
{"rsnAllocationSyncAll", "(III)V", (void*)nAllocationSyncAll },
+{"rsnAllocationGetSurfaceTextureID", "(II)I", (void*)nAllocationGetSurfaceTextureID },
{"rsnAllocationData1D", "(IIIII[II)V", (void*)nAllocationData1D_i },
{"rsnAllocationData1D", "(IIIII[SI)V", (void*)nAllocationData1D_s },
{"rsnAllocationData1D", "(IIIII[BI)V", (void*)nAllocationData1D_b },
diff --git a/include/binder/BinderService.h b/include/binder/BinderService.h
index 2316fef..ca594d3 100644
--- a/include/binder/BinderService.h
+++ b/include/binder/BinderService.h
@@ -34,15 +34,15 @@
class BinderService
{
public:
- static status_t publish() {
+ static status_t publish(bool allowIsolated = false) {
sp<IServiceManager> sm(defaultServiceManager());
- return sm->addService(String16(SERVICE::getServiceName()), new SERVICE());
+ return sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated);
}
- static void publishAndJoinThreadPool() {
+ static void publishAndJoinThreadPool(bool allowIsolated = false) {
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm(defaultServiceManager());
- sm->addService(String16(SERVICE::getServiceName()), new SERVICE());
+ sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated);
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
diff --git a/include/binder/IServiceManager.h b/include/binder/IServiceManager.h
index 24e9e99..2c297d6 100644
--- a/include/binder/IServiceManager.h
+++ b/include/binder/IServiceManager.h
@@ -47,7 +47,8 @@
* Register a service.
*/
virtual status_t addService( const String16& name,
- const sp<IBinder>& service) = 0;
+ const sp<IBinder>& service,
+ bool allowIsolated = false) = 0;
/**
* Return list of all existing services.
diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h
new file mode 100644
index 0000000..991a181
--- /dev/null
+++ b/include/gui/BufferQueue.h
@@ -0,0 +1,343 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_GUI_BUFFERQUEUE_H
+#define ANDROID_GUI_BUFFERQUEUE_H
+
+#include <EGL/egl.h>
+
+#include <gui/ISurfaceTexture.h>
+
+#include <surfaceflinger/IGraphicBufferAlloc.h>
+#include <ui/GraphicBuffer.h>
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+#include <utils/threads.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+class BufferQueue : public BnSurfaceTexture {
+public:
+ enum { MIN_UNDEQUEUED_BUFFERS = 2 };
+ enum {
+ MIN_ASYNC_BUFFER_SLOTS = MIN_UNDEQUEUED_BUFFERS + 1,
+ MIN_SYNC_BUFFER_SLOTS = MIN_UNDEQUEUED_BUFFERS
+ };
+ enum { NUM_BUFFER_SLOTS = 32 };
+ enum { NO_CONNECTED_API = 0 };
+
+ struct FrameAvailableListener : public virtual RefBase {
+ // onFrameAvailable() is called from queueBuffer() each time an
+ // additional frame becomes available for consumption. This means that
+ // frames that are queued while in asynchronous mode only trigger the
+ // callback if no previous frames are pending. Frames queued while in
+ // synchronous mode always trigger the callback.
+ //
+ // This is called without any lock held and can be called concurrently
+ // by multiple threads.
+ virtual void onFrameAvailable() = 0;
+ };
+
+ // BufferQueue manages a pool of gralloc memory slots to be used
+ // by producers and consumers.
+ // allowSynchronousMode specifies whether or not synchronous mode can be
+ // enabled.
+ BufferQueue(bool allowSynchronousMode = true);
+ virtual ~BufferQueue();
+
+ // setBufferCount updates the number of available buffer slots. After
+ // calling this all buffer slots are both unallocated and owned by the
+ // BufferQueue object (i.e. they are not owned by the client).
+ virtual status_t setBufferCount(int bufferCount);
+
+ virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf);
+
+ // dequeueBuffer gets the next buffer slot index for the client to use. If a
+ // buffer slot is available then that slot index is written to the location
+ // pointed to by the buf argument and a status of OK is returned. If no
+ // slot is available then a status of -EBUSY is returned and buf is
+ // unmodified.
+ // The width and height parameters must be no greater than the minimum of
+ // GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv).
+ // An error due to invalid dimensions might not be reported until
+ // updateTexImage() is called.
+ virtual status_t dequeueBuffer(int *buf, uint32_t width, uint32_t height,
+ uint32_t format, uint32_t usage);
+
+ // queueBuffer returns a filled buffer to the BufferQueue. In addition, a
+ // timestamp must be provided for the buffer. The timestamp is in
+ // nanoseconds, and must be monotonically increasing. Its other semantics
+ // (zero point, etc) are client-dependent and should be documented by the
+ // client.
+ virtual status_t queueBuffer(int buf, int64_t timestamp,
+ uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform);
+ virtual void cancelBuffer(int buf);
+ virtual status_t setCrop(const Rect& reg);
+ virtual status_t setTransform(uint32_t transform);
+ virtual status_t setScalingMode(int mode);
+
+ // setSynchronousMode set whether dequeueBuffer is synchronous or
+ // asynchronous. In synchronous mode, dequeueBuffer blocks until
+ // a buffer is available, the currently bound buffer can be dequeued and
+ // queued buffers will be retired in order.
+ // The default mode is asynchronous.
+ virtual status_t setSynchronousMode(bool enabled);
+
+ // connect attempts to connect a producer client API to the BufferQueue.
+ // This must be called before any other ISurfaceTexture methods are called
+ // except for getAllocator.
+ //
+ // This method will fail if the connect was previously called on the
+ // BufferQueue and no corresponding disconnect call was made.
+ virtual status_t connect(int api,
+ uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform);
+
+ // disconnect attempts to disconnect a producer client API from the
+ // BufferQueue. Calling this method will cause any subsequent calls to other
+ // ISurfaceTexture methods to fail except for getAllocator and connect.
+ // Successfully calling connect after this will allow the other methods to
+ // succeed again.
+ //
+ // This method will fail if the the BufferQueue is not currently
+ // connected to the specified client API.
+ virtual status_t disconnect(int api);
+
+protected:
+
+ // freeBufferLocked frees the resources (both GraphicBuffer and EGLImage)
+ // for the given slot.
+ void freeBufferLocked(int index);
+
+ // freeAllBuffersLocked frees the resources (both GraphicBuffer and
+ // EGLImage) for all slots.
+ void freeAllBuffersLocked();
+
+ // freeAllBuffersExceptHeadLocked frees the resources (both GraphicBuffer
+ // and EGLImage) for all slots except the head of mQueue
+ void freeAllBuffersExceptHeadLocked();
+
+ // drainQueueLocked drains the buffer queue if we're in synchronous mode
+ // returns immediately otherwise. It returns NO_INIT if the BufferQueue
+ // became abandoned or disconnected during this call.
+ status_t drainQueueLocked();
+
+ // drainQueueAndFreeBuffersLocked drains the buffer queue if we're in
+ // synchronous mode and free all buffers. In asynchronous mode, all buffers
+ // are freed except the current buffer.
+ status_t drainQueueAndFreeBuffersLocked();
+
+ status_t setBufferCountServerLocked(int bufferCount);
+
+ enum { INVALID_BUFFER_SLOT = -1 };
+
+ struct BufferSlot {
+
+ BufferSlot()
+ : mEglImage(EGL_NO_IMAGE_KHR),
+ mEglDisplay(EGL_NO_DISPLAY),
+ mBufferState(BufferSlot::FREE),
+ mRequestBufferCalled(false),
+ mTransform(0),
+ mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
+ mTimestamp(0),
+ mFrameNumber(0),
+ mFence(EGL_NO_SYNC_KHR) {
+ mCrop.makeInvalid();
+ }
+
+ // mGraphicBuffer points to the buffer allocated for this slot or is NULL
+ // if no buffer has been allocated.
+ sp<GraphicBuffer> mGraphicBuffer;
+
+ // mEglImage is the EGLImage created from mGraphicBuffer.
+ EGLImageKHR mEglImage;
+
+ // mEglDisplay is the EGLDisplay used to create mEglImage.
+ EGLDisplay mEglDisplay;
+
+ // BufferState represents the different states in which a buffer slot
+ // can be.
+ enum BufferState {
+ // FREE indicates that the buffer is not currently being used and
+ // will not be used in the future until it gets dequeued and
+ // subsequently queued by the client.
+ FREE = 0,
+
+ // DEQUEUED indicates that the buffer has been dequeued by the
+ // client, but has not yet been queued or canceled. The buffer is
+ // considered 'owned' by the client, and the server should not use
+ // it for anything.
+ //
+ // Note that when in synchronous-mode (mSynchronousMode == true),
+ // the buffer that's currently attached to the texture may be
+ // dequeued by the client. That means that the current buffer can
+ // be in either the DEQUEUED or QUEUED state. In asynchronous mode,
+ // however, the current buffer is always in the QUEUED state.
+ DEQUEUED = 1,
+
+ // QUEUED indicates that the buffer has been queued by the client,
+ // and has not since been made available for the client to dequeue.
+ // Attaching the buffer to the texture does NOT transition the
+ // buffer away from the QUEUED state. However, in Synchronous mode
+ // the current buffer may be dequeued by the client under some
+ // circumstances. See the note about the current buffer in the
+ // documentation for DEQUEUED.
+ QUEUED = 2,
+ };
+
+ // mBufferState is the current state of this buffer slot.
+ BufferState mBufferState;
+
+ // mRequestBufferCalled is used for validating that the client did
+ // call requestBuffer() when told to do so. Technically this is not
+ // needed but useful for debugging and catching client bugs.
+ bool mRequestBufferCalled;
+
+ // mCrop is the current crop rectangle for this buffer slot. This gets
+ // set to mNextCrop each time queueBuffer gets called for this buffer.
+ Rect mCrop;
+
+ // mTransform is the current transform flags for this buffer slot. This
+ // gets set to mNextTransform each time queueBuffer gets called for this
+ // slot.
+ uint32_t mTransform;
+
+ // mScalingMode is the current scaling mode for this buffer slot. This
+ // gets set to mNextScalingMode each time queueBuffer gets called for
+ // this slot.
+ uint32_t mScalingMode;
+
+ // mTimestamp is the current timestamp for this buffer slot. This gets
+ // to set by queueBuffer each time this slot is queued.
+ int64_t mTimestamp;
+
+ // mFrameNumber is the number of the queued frame for this slot.
+ uint64_t mFrameNumber;
+
+ // mFence is the EGL sync object that must signal before the buffer
+ // associated with this buffer slot may be dequeued. It is initialized
+ // to EGL_NO_SYNC_KHR when the buffer is created and (optionally, based
+ // on a compile-time option) set to a new sync object in updateTexImage.
+ EGLSyncKHR mFence;
+ };
+
+ // mSlots is the array of buffer slots that must be mirrored on the client
+ // side. This allows buffer ownership to be transferred between the client
+ // and server without sending a GraphicBuffer over binder. The entire array
+ // is initialized to NULL at construction time, and buffers are allocated
+ // for a slot when requestBuffer is called with that slot's index.
+ BufferSlot mSlots[NUM_BUFFER_SLOTS];
+
+
+ // mDefaultWidth holds the default width of allocated buffers. It is used
+ // in requestBuffers() if a width and height of zero is specified.
+ uint32_t mDefaultWidth;
+
+ // mDefaultHeight holds the default height of allocated buffers. It is used
+ // in requestBuffers() if a width and height of zero is specified.
+ uint32_t mDefaultHeight;
+
+ // mPixelFormat holds the pixel format of allocated buffers. It is used
+ // in requestBuffers() if a format of zero is specified.
+ uint32_t mPixelFormat;
+
+ // mBufferCount is the number of buffer slots that the client and server
+ // must maintain. It defaults to MIN_ASYNC_BUFFER_SLOTS and can be changed
+ // by calling setBufferCount or setBufferCountServer
+ int mBufferCount;
+
+ // mClientBufferCount is the number of buffer slots requested by the client.
+ // The default is zero, which means the client doesn't care how many buffers
+ // there is.
+ int mClientBufferCount;
+
+ // mServerBufferCount buffer count requested by the server-side
+ int mServerBufferCount;
+
+ // mCurrentTexture is the buffer slot index of the buffer that is currently
+ // bound to the OpenGL texture. It is initialized to INVALID_BUFFER_SLOT,
+ // indicating that no buffer slot is currently bound to the texture. Note,
+ // however, that a value of INVALID_BUFFER_SLOT does not necessarily mean
+ // that no buffer is bound to the texture. A call to setBufferCount will
+ // reset mCurrentTexture to INVALID_BUFFER_SLOT.
+ int mCurrentTexture;
+
+ // mNextCrop is the crop rectangle that will be used for the next buffer
+ // that gets queued. It is set by calling setCrop.
+ Rect mNextCrop;
+
+ // mNextTransform is the transform identifier that will be used for the next
+ // buffer that gets queued. It is set by calling setTransform.
+ uint32_t mNextTransform;
+
+ // mNextScalingMode is the scaling mode that will be used for the next
+ // buffers that get queued. It is set by calling setScalingMode.
+ int mNextScalingMode;
+
+ // mGraphicBufferAlloc is the connection to SurfaceFlinger that is used to
+ // allocate new GraphicBuffer objects.
+ sp<IGraphicBufferAlloc> mGraphicBufferAlloc;
+
+ // mFrameAvailableListener is the listener object that will be called when a
+ // new frame becomes available. If it is not NULL it will be called from
+ // queueBuffer.
+ sp<FrameAvailableListener> mFrameAvailableListener;
+
+ // mSynchronousMode whether we're in synchronous mode or not
+ bool mSynchronousMode;
+
+ // mAllowSynchronousMode whether we allow synchronous mode or not
+ const bool mAllowSynchronousMode;
+
+ // mConnectedApi indicates the API that is currently connected to this
+ // BufferQueue. It defaults to NO_CONNECTED_API (= 0), and gets updated
+ // by the connect and disconnect methods.
+ int mConnectedApi;
+
+ // mDequeueCondition condition used for dequeueBuffer in synchronous mode
+ mutable Condition mDequeueCondition;
+
+ // mQueue is a FIFO of queued buffers used in synchronous mode
+ typedef Vector<int> Fifo;
+ Fifo mQueue;
+
+ // mAbandoned indicates that the BufferQueue will no longer be used to
+ // consume images buffers pushed to it using the ISurfaceTexture interface.
+ // It is initialized to false, and set to true in the abandon method. A
+ // BufferQueue that has been abandoned will return the NO_INIT error from
+ // all ISurfaceTexture methods capable of returning an error.
+ bool mAbandoned;
+
+ // mName is a string used to identify the BufferQueue in log messages.
+ // It is set by the setName method.
+ String8 mName;
+
+ // mMutex is the mutex used to prevent concurrent access to the member
+ // variables of BufferQueue objects. It must be locked whenever the
+ // member variables are accessed.
+ mutable Mutex mMutex;
+
+ // mFrameCounter is the free running counter, incremented for every buffer queued
+ // with the surface Texture.
+ uint64_t mFrameCounter;
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_GUI_BUFFERQUEUE_H
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index a8c7672..4318f0f 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -23,6 +23,7 @@
#include <GLES2/gl2ext.h>
#include <gui/ISurfaceTexture.h>
+#include <gui/BufferQueue.h>
#include <ui/GraphicBuffer.h>
@@ -35,30 +36,11 @@
namespace android {
// ----------------------------------------------------------------------------
-class IGraphicBufferAlloc;
+
class String8;
-class SurfaceTexture : public BnSurfaceTexture {
+class SurfaceTexture : public BufferQueue {
public:
- enum { MIN_UNDEQUEUED_BUFFERS = 2 };
- enum {
- MIN_ASYNC_BUFFER_SLOTS = MIN_UNDEQUEUED_BUFFERS + 1,
- MIN_SYNC_BUFFER_SLOTS = MIN_UNDEQUEUED_BUFFERS
- };
- enum { NUM_BUFFER_SLOTS = 32 };
- enum { NO_CONNECTED_API = 0 };
-
- struct FrameAvailableListener : public virtual RefBase {
- // onFrameAvailable() is called from queueBuffer() each time an
- // additional frame becomes available for consumption. This means that
- // frames that are queued while in asynchronous mode only trigger the
- // callback if no previous frames are pending. Frames queued while in
- // synchronous mode always trigger the callback.
- //
- // This is called without any lock held and can be called concurrently
- // by multiple threads.
- virtual void onFrameAvailable() = 0;
- };
// SurfaceTexture constructs a new SurfaceTexture object. tex indicates the
// name of the OpenGL ES texture to which images are to be streamed. This
@@ -73,65 +55,8 @@
virtual ~SurfaceTexture();
- // setBufferCount updates the number of available buffer slots. After
- // calling this all buffer slots are both unallocated and owned by the
- // SurfaceTexture object (i.e. they are not owned by the client).
- virtual status_t setBufferCount(int bufferCount);
-
- virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf);
-
- // dequeueBuffer gets the next buffer slot index for the client to use. If a
- // buffer slot is available then that slot index is written to the location
- // pointed to by the buf argument and a status of OK is returned. If no
- // slot is available then a status of -EBUSY is returned and buf is
- // unmodified.
- // The width and height parameters must be no greater than the minimum of
- // GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv).
- // An error due to invalid dimensions might not be reported until
- // updateTexImage() is called.
- virtual status_t dequeueBuffer(int *buf, uint32_t width, uint32_t height,
- uint32_t format, uint32_t usage);
-
- // queueBuffer returns a filled buffer to the SurfaceTexture. In addition, a
- // timestamp must be provided for the buffer. The timestamp is in
- // nanoseconds, and must be monotonically increasing. Its other semantics
- // (zero point, etc) are client-dependent and should be documented by the
- // client.
- virtual status_t queueBuffer(int buf, int64_t timestamp,
- uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform);
- virtual void cancelBuffer(int buf);
- virtual status_t setCrop(const Rect& reg);
- virtual status_t setTransform(uint32_t transform);
- virtual status_t setScalingMode(int mode);
-
virtual int query(int what, int* value);
- // setSynchronousMode set whether dequeueBuffer is synchronous or
- // asynchronous. In synchronous mode, dequeueBuffer blocks until
- // a buffer is available, the currently bound buffer can be dequeued and
- // queued buffers will be retired in order.
- // The default mode is asynchronous.
- virtual status_t setSynchronousMode(bool enabled);
-
- // connect attempts to connect a client API to the SurfaceTexture. This
- // must be called before any other ISurfaceTexture methods are called except
- // for getAllocator.
- //
- // This method will fail if the connect was previously called on the
- // SurfaceTexture and no corresponding disconnect call was made.
- virtual status_t connect(int api,
- uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform);
-
- // disconnect attempts to disconnect a client API from the SurfaceTexture.
- // Calling this method will cause any subsequent calls to other
- // ISurfaceTexture methods to fail except for getAllocator and connect.
- // Successfully calling connect after this will allow the other methods to
- // succeed again.
- //
- // This method will fail if the the SurfaceTexture is not currently
- // connected to the specified client API.
- virtual status_t disconnect(int api);
-
// updateTexImage sets the image contents of the target texture to that of
// the most recently queued buffer.
//
@@ -233,28 +158,6 @@
protected:
- // freeBufferLocked frees the resources (both GraphicBuffer and EGLImage)
- // for the given slot.
- void freeBufferLocked(int index);
-
- // freeAllBuffersLocked frees the resources (both GraphicBuffer and
- // EGLImage) for all slots.
- void freeAllBuffersLocked();
-
- // freeAllBuffersExceptHeadLocked frees the resources (both GraphicBuffer
- // and EGLImage) for all slots except the head of mQueue
- void freeAllBuffersExceptHeadLocked();
-
- // drainQueueLocked drains the buffer queue if we're in synchronous mode
- // returns immediately otherwise. return NO_INIT if SurfaceTexture
- // became abandoned or disconnected during this call.
- status_t drainQueueLocked();
-
- // drainQueueAndFreeBuffersLocked drains the buffer queue if we're in
- // synchronous mode and free all buffers. In asynchronous mode, all buffers
- // are freed except the current buffer.
- status_t drainQueueAndFreeBuffersLocked();
-
static bool isExternalFormat(uint32_t format);
private:
@@ -263,146 +166,11 @@
EGLImageKHR createImage(EGLDisplay dpy,
const sp<GraphicBuffer>& graphicBuffer);
- status_t setBufferCountServerLocked(int bufferCount);
-
// computeCurrentTransformMatrix computes the transform matrix for the
// current texture. It uses mCurrentTransform and the current GraphicBuffer
// to compute this matrix and stores it in mCurrentTransformMatrix.
void computeCurrentTransformMatrix();
- enum { INVALID_BUFFER_SLOT = -1 };
-
- struct BufferSlot {
-
- BufferSlot()
- : mEglImage(EGL_NO_IMAGE_KHR),
- mEglDisplay(EGL_NO_DISPLAY),
- mBufferState(BufferSlot::FREE),
- mRequestBufferCalled(false),
- mTransform(0),
- mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
- mTimestamp(0),
- mFrameNumber(0),
- mFence(EGL_NO_SYNC_KHR) {
- mCrop.makeInvalid();
- }
-
- // mGraphicBuffer points to the buffer allocated for this slot or is NULL
- // if no buffer has been allocated.
- sp<GraphicBuffer> mGraphicBuffer;
-
- // mEglImage is the EGLImage created from mGraphicBuffer.
- EGLImageKHR mEglImage;
-
- // mEglDisplay is the EGLDisplay used to create mEglImage.
- EGLDisplay mEglDisplay;
-
- // BufferState represents the different states in which a buffer slot
- // can be.
- enum BufferState {
- // FREE indicates that the buffer is not currently being used and
- // will not be used in the future until it gets dequeued and
- // subsequently queued by the client.
- FREE = 0,
-
- // DEQUEUED indicates that the buffer has been dequeued by the
- // client, but has not yet been queued or canceled. The buffer is
- // considered 'owned' by the client, and the server should not use
- // it for anything.
- //
- // Note that when in synchronous-mode (mSynchronousMode == true),
- // the buffer that's currently attached to the texture may be
- // dequeued by the client. That means that the current buffer can
- // be in either the DEQUEUED or QUEUED state. In asynchronous mode,
- // however, the current buffer is always in the QUEUED state.
- DEQUEUED = 1,
-
- // QUEUED indicates that the buffer has been queued by the client,
- // and has not since been made available for the client to dequeue.
- // Attaching the buffer to the texture does NOT transition the
- // buffer away from the QUEUED state. However, in Synchronous mode
- // the current buffer may be dequeued by the client under some
- // circumstances. See the note about the current buffer in the
- // documentation for DEQUEUED.
- QUEUED = 2,
- };
-
- // mBufferState is the current state of this buffer slot.
- BufferState mBufferState;
-
- // mRequestBufferCalled is used for validating that the client did
- // call requestBuffer() when told to do so. Technically this is not
- // needed but useful for debugging and catching client bugs.
- bool mRequestBufferCalled;
-
- // mCrop is the current crop rectangle for this buffer slot. This gets
- // set to mNextCrop each time queueBuffer gets called for this buffer.
- Rect mCrop;
-
- // mTransform is the current transform flags for this buffer slot. This
- // gets set to mNextTransform each time queueBuffer gets called for this
- // slot.
- uint32_t mTransform;
-
- // mScalingMode is the current scaling mode for this buffer slot. This
- // gets set to mNextScalingMode each time queueBuffer gets called for
- // this slot.
- uint32_t mScalingMode;
-
- // mTimestamp is the current timestamp for this buffer slot. This gets
- // to set by queueBuffer each time this slot is queued.
- int64_t mTimestamp;
-
- // mFrameNumber is the number of the queued frame for this slot.
- uint64_t mFrameNumber;
-
- // mFence is the EGL sync object that must signal before the buffer
- // associated with this buffer slot may be dequeued. It is initialized
- // to EGL_NO_SYNC_KHR when the buffer is created and (optionally, based
- // on a compile-time option) set to a new sync object in updateTexImage.
- EGLSyncKHR mFence;
- };
-
- // mSlots is the array of buffer slots that must be mirrored on the client
- // side. This allows buffer ownership to be transferred between the client
- // and server without sending a GraphicBuffer over binder. The entire array
- // is initialized to NULL at construction time, and buffers are allocated
- // for a slot when requestBuffer is called with that slot's index.
- BufferSlot mSlots[NUM_BUFFER_SLOTS];
-
- // mDefaultWidth holds the default width of allocated buffers. It is used
- // in requestBuffers() if a width and height of zero is specified.
- uint32_t mDefaultWidth;
-
- // mDefaultHeight holds the default height of allocated buffers. It is used
- // in requestBuffers() if a width and height of zero is specified.
- uint32_t mDefaultHeight;
-
- // mPixelFormat holds the pixel format of allocated buffers. It is used
- // in requestBuffers() if a format of zero is specified.
- uint32_t mPixelFormat;
-
- // mBufferCount is the number of buffer slots that the client and server
- // must maintain. It defaults to MIN_ASYNC_BUFFER_SLOTS and can be changed
- // by calling setBufferCount or setBufferCountServer
- int mBufferCount;
-
- // mClientBufferCount is the number of buffer slots requested by the client.
- // The default is zero, which means the client doesn't care how many buffers
- // there is.
- int mClientBufferCount;
-
- // mServerBufferCount buffer count requested by the server-side
- int mServerBufferCount;
-
- // mCurrentTexture is the buffer slot index of the buffer that is currently
- // bound to the OpenGL texture. It is initialized to INVALID_BUFFER_SLOT,
- // indicating that no buffer slot is currently bound to the texture. Note,
- // however, that a value of INVALID_BUFFER_SLOT does not necessarily mean
- // that no buffer is bound to the texture. A call to setBufferCount will
- // reset mCurrentTexture to INVALID_BUFFER_SLOT.
- int mCurrentTexture;
-
// mCurrentTextureBuf is the graphic buffer of the current texture. It's
// possible that this buffer is not associated with any buffer slot, so we
// must track it separately in order to support the getCurrentBuffer method.
@@ -429,72 +197,17 @@
// gets set each time updateTexImage is called.
int64_t mCurrentTimestamp;
- // mNextCrop is the crop rectangle that will be used for the next buffer
- // that gets queued. It is set by calling setCrop.
- Rect mNextCrop;
-
- // mNextTransform is the transform identifier that will be used for the next
- // buffer that gets queued. It is set by calling setTransform.
- uint32_t mNextTransform;
-
- // mNextScalingMode is the scaling mode that will be used for the next
- // buffers that get queued. It is set by calling setScalingMode.
- int mNextScalingMode;
-
// mTexName is the name of the OpenGL texture to which streamed images will
// be bound when updateTexImage is called. It is set at construction time
// changed with a call to setTexName.
const GLuint mTexName;
- // mGraphicBufferAlloc is the connection to SurfaceFlinger that is used to
- // allocate new GraphicBuffer objects.
- sp<IGraphicBufferAlloc> mGraphicBufferAlloc;
-
- // mFrameAvailableListener is the listener object that will be called when a
- // new frame becomes available. If it is not NULL it will be called from
- // queueBuffer.
- sp<FrameAvailableListener> mFrameAvailableListener;
-
- // mSynchronousMode whether we're in synchronous mode or not
- bool mSynchronousMode;
-
- // mAllowSynchronousMode whether we allow synchronous mode or not
- const bool mAllowSynchronousMode;
-
- // mConnectedApi indicates the API that is currently connected to this
- // SurfaceTexture. It defaults to NO_CONNECTED_API (= 0), and gets updated
- // by the connect and disconnect methods.
- int mConnectedApi;
-
- // mDequeueCondition condition used for dequeueBuffer in synchronous mode
- mutable Condition mDequeueCondition;
-
- // mQueue is a FIFO of queued buffers used in synchronous mode
- typedef Vector<int> Fifo;
- Fifo mQueue;
-
- // mAbandoned indicates that the SurfaceTexture will no longer be used to
- // consume images buffers pushed to it using the ISurfaceTexture interface.
- // It is initialized to false, and set to true in the abandon method. A
- // SurfaceTexture that has been abandoned will return the NO_INIT error from
- // all ISurfaceTexture methods capable of returning an error.
- bool mAbandoned;
-
- // mName is a string used to identify the SurfaceTexture in log messages.
- // It is set by the setName method.
- String8 mName;
-
// mUseFenceSync indicates whether creation of the EGL_KHR_fence_sync
// extension should be used to prevent buffers from being dequeued before
// it's safe for them to be written. It gets set at construction time and
// never changes.
const bool mUseFenceSync;
- // mMutex is the mutex used to prevent concurrent access to the member
- // variables of SurfaceTexture objects. It must be locked whenever the
- // member variables are accessed.
- mutable Mutex mMutex;
-
// mTexTarget is the GL texture target with which the GL texture object is
// associated. It is set in the constructor and never changed. It is
// almost always GL_TEXTURE_EXTERNAL_OES except for one use case in Android
@@ -504,11 +217,6 @@
// browser's tile cache exceeds.
const GLenum mTexTarget;
- // mFrameCounter is the free running counter, incremented for every buffer queued
- // with the surface Texture.
- uint64_t mFrameCounter;
-
-
};
// ----------------------------------------------------------------------------
diff --git a/include/media/AudioEffect.h b/include/media/AudioEffect.h
index 7b0b443..02dfc1b 100644
--- a/include/media/AudioEffect.h
+++ b/include/media/AudioEffect.h
@@ -108,7 +108,8 @@
* Returned value
* *descriptor updated with effect descriptor
*/
- static status_t getEffectDescriptor(effect_uuid_t *uuid, effect_descriptor_t *descriptor);
+ static status_t getEffectDescriptor(const effect_uuid_t *uuid,
+ effect_descriptor_t *descriptor) /*const*/;
/*
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index c8c5dba..ca57f9e 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -344,7 +344,6 @@
virtual status_t readyToRun() { return NO_ERROR; }
virtual void onFirstRef() {}
AudioRecord& mReceiver;
- Mutex mLock;
};
bool processAudioBuffer(const sp<ClientRecordThread>& thread);
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 74a1e62..da99620 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -55,8 +55,10 @@
static status_t getMasterMute(bool* mute);
// set/get stream volume on specified output
- static status_t setStreamVolume(audio_stream_type_t stream, float value, int output);
- static status_t getStreamVolume(audio_stream_type_t stream, float* volume, int output);
+ static status_t setStreamVolume(audio_stream_type_t stream, float value,
+ audio_io_handle_t output);
+ static status_t getStreamVolume(audio_stream_type_t stream, float* volume,
+ audio_io_handle_t output);
// mute/unmute stream
static status_t setStreamMute(audio_stream_type_t stream, bool mute);
@@ -217,7 +219,7 @@
// indicate a change in the configuration of an output or input: keeps the cached
// values for output/input parameters upto date in client process
- virtual void ioConfigChanged(int event, int ioHandle, void *param2);
+ virtual void ioConfigChanged(int event, audio_io_handle_t ioHandle, void *param2);
};
class AudioPolicyServiceClient: public IBinder::DeathRecipient
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 02c85cd..11db81b 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -273,18 +273,18 @@
* left and right volumes. Levels must be >= 0.0 and <= 1.0.
*/
status_t setVolume(float left, float right);
- void getVolume(float* left, float* right);
+ void getVolume(float* left, float* right) const;
/* Set the send level for this track. An auxiliary effect should be attached
* to the track with attachEffect(). Level must be >= 0.0 and <= 1.0.
*/
status_t setAuxEffectSendLevel(float level);
- void getAuxEffectSendLevel(float* level);
+ void getAuxEffectSendLevel(float* level) const;
/* Set sample rate for this track, mostly used for games' sound effects
*/
status_t setSampleRate(int sampleRate);
- uint32_t getSampleRate();
+ uint32_t getSampleRate() const;
/* Enables looping and sets the start and end points of looping.
*
@@ -299,7 +299,7 @@
* (loopEnd-loopStart) <= framecount()
*/
status_t setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount);
- status_t getLoop(uint32_t *loopStart, uint32_t *loopEnd, int *loopCount);
+ status_t getLoop(uint32_t *loopStart, uint32_t *loopEnd, int *loopCount) const;
/* Sets marker position. When playback reaches the number of frames specified, a callback with
* event type EVENT_MARKER is called. Calling setMarkerPosition with marker == 0 cancels marker
@@ -315,7 +315,7 @@
* - INVALID_OPERATION: the AudioTrack has no callback installed.
*/
status_t setMarkerPosition(uint32_t marker);
- status_t getMarkerPosition(uint32_t *marker);
+ status_t getMarkerPosition(uint32_t *marker) const;
/* Sets position update period. Every time the number of frames specified has been played,
@@ -333,7 +333,7 @@
* - INVALID_OPERATION: the AudioTrack has no callback installed.
*/
status_t setPositionUpdatePeriod(uint32_t updatePeriod);
- status_t getPositionUpdatePeriod(uint32_t *updatePeriod);
+ status_t getPositionUpdatePeriod(uint32_t *updatePeriod) const;
/* Sets playback head position within AudioTrack buffer. The new position is specified
* in number of frames.
@@ -384,7 +384,7 @@
* Returned value:
* AudioTrack session ID.
*/
- int getSessionId();
+ int getSessionId() const;
/* Attach track auxiliary output to specified effect. Use effectId = 0
* to detach track from effect.
@@ -446,7 +446,6 @@
virtual status_t readyToRun();
virtual void onFirstRef();
AudioTrack& mReceiver;
- Mutex mLock;
};
bool processAudioBuffer(const sp<AudioTrackThread>& thread);
diff --git a/include/media/EffectsFactoryApi.h b/include/media/EffectsFactoryApi.h
index 8ae13cc..df83995 100644
--- a/include/media/EffectsFactoryApi.h
+++ b/include/media/EffectsFactoryApi.h
@@ -109,7 +109,7 @@
// *pHandle: updated with the effect handle.
//
////////////////////////////////////////////////////////////////////////////////
-int EffectCreate(effect_uuid_t *pEffectUuid, int32_t sessionId, int32_t ioId, effect_handle_t *pHandle);
+int EffectCreate(const effect_uuid_t *pEffectUuid, int32_t sessionId, int32_t ioId, effect_handle_t *pHandle);
////////////////////////////////////////////////////////////////////////////////
//
@@ -151,7 +151,7 @@
// *pDescriptor: updated with the effect descriptor.
//
////////////////////////////////////////////////////////////////////////////////
-int EffectGetDescriptor(effect_uuid_t *pEffectUuid, effect_descriptor_t *pDescriptor);
+int EffectGetDescriptor(const effect_uuid_t *pEffectUuid, effect_descriptor_t *pDescriptor);
////////////////////////////////////////////////////////////////////////////////
//
@@ -167,7 +167,7 @@
// 1 if uuid is equal to EFFECT_UUID_NULL.
//
////////////////////////////////////////////////////////////////////////////////
-int EffectIsNullUuid(effect_uuid_t *pEffectUuid);
+int EffectIsNullUuid(const effect_uuid_t *pEffectUuid);
#if __cplusplus
} // extern "C"
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index 760595c..433ce7c 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -27,6 +27,7 @@
#include <media/IAudioTrack.h>
#include <media/IAudioRecord.h>
#include <media/IAudioFlingerClient.h>
+#include <system/audio.h>
#include <hardware/audio_effect.h>
#include <media/IEffect.h>
#include <media/IEffectClient.h>
@@ -53,13 +54,13 @@
int frameCount,
uint32_t flags,
const sp<IMemory>& sharedBuffer,
- int output,
+ audio_io_handle_t output,
int *sessionId,
status_t *status) = 0;
virtual sp<IAudioRecord> openRecord(
pid_t pid,
- int input,
+ audio_io_handle_t input,
uint32_t sampleRate,
audio_format_t format,
uint32_t channelMask,
@@ -71,11 +72,11 @@
/* query the audio hardware state. This state never changes,
* and therefore can be cached.
*/
- virtual uint32_t sampleRate(int output) const = 0;
- virtual int channelCount(int output) const = 0;
- virtual audio_format_t format(int output) const = 0;
- virtual size_t frameCount(int output) const = 0;
- virtual uint32_t latency(int output) const = 0;
+ virtual uint32_t sampleRate(audio_io_handle_t output) const = 0;
+ virtual int channelCount(audio_io_handle_t output) const = 0;
+ virtual audio_format_t format(audio_io_handle_t output) const = 0;
+ virtual size_t frameCount(audio_io_handle_t output) const = 0;
+ virtual uint32_t latency(audio_io_handle_t output) const = 0;
/* set/get the audio hardware state. This will probably be used by
* the preference panel, mostly.
@@ -89,10 +90,12 @@
/* set/get stream type state. This will probably be used by
* the preference panel, mostly.
*/
- virtual status_t setStreamVolume(audio_stream_type_t stream, float value, int output) = 0;
+ virtual status_t setStreamVolume(audio_stream_type_t stream, float value,
+ audio_io_handle_t output) = 0;
virtual status_t setStreamMute(audio_stream_type_t stream, bool muted) = 0;
- virtual float streamVolume(audio_stream_type_t stream, int output) const = 0;
+ virtual float streamVolume(audio_stream_type_t stream,
+ audio_io_handle_t output) const = 0;
virtual bool streamMute(audio_stream_type_t stream) const = 0;
// set audio mode
@@ -102,63 +105,68 @@
virtual status_t setMicMute(bool state) = 0;
virtual bool getMicMute() const = 0;
- virtual status_t setParameters(int ioHandle, const String8& keyValuePairs) = 0;
- virtual String8 getParameters(int ioHandle, const String8& keys) = 0;
+ virtual status_t setParameters(audio_io_handle_t ioHandle,
+ const String8& keyValuePairs) = 0;
+ virtual String8 getParameters(audio_io_handle_t ioHandle, const String8& keys) const = 0;
// register a current process for audio output change notifications
virtual void registerClient(const sp<IAudioFlingerClient>& client) = 0;
// retrieve the audio recording buffer size
- virtual size_t getInputBufferSize(uint32_t sampleRate, audio_format_t format, int channelCount) = 0;
+ virtual size_t getInputBufferSize(uint32_t sampleRate, audio_format_t format, int channelCount) const = 0;
- virtual int openOutput(uint32_t *pDevices,
+ virtual audio_io_handle_t openOutput(uint32_t *pDevices,
uint32_t *pSamplingRate,
audio_format_t *pFormat,
uint32_t *pChannels,
uint32_t *pLatencyMs,
uint32_t flags) = 0;
- virtual int openDuplicateOutput(int output1, int output2) = 0;
- virtual status_t closeOutput(int output) = 0;
- virtual status_t suspendOutput(int output) = 0;
- virtual status_t restoreOutput(int output) = 0;
+ virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1,
+ audio_io_handle_t output2) = 0;
+ virtual status_t closeOutput(audio_io_handle_t output) = 0;
+ virtual status_t suspendOutput(audio_io_handle_t output) = 0;
+ virtual status_t restoreOutput(audio_io_handle_t output) = 0;
- virtual int openInput(uint32_t *pDevices,
+ virtual audio_io_handle_t openInput(uint32_t *pDevices,
uint32_t *pSamplingRate,
audio_format_t *pFormat,
uint32_t *pChannels,
audio_in_acoustics_t acoustics) = 0;
- virtual status_t closeInput(int input) = 0;
+ virtual status_t closeInput(audio_io_handle_t input) = 0;
- virtual status_t setStreamOutput(audio_stream_type_t stream, int output) = 0;
+ virtual status_t setStreamOutput(audio_stream_type_t stream, audio_io_handle_t output) = 0;
virtual status_t setVoiceVolume(float volume) = 0;
- virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, int output) = 0;
+ virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames,
+ audio_io_handle_t output) const = 0;
- virtual unsigned int getInputFramesLost(int ioHandle) = 0;
+ virtual unsigned int getInputFramesLost(audio_io_handle_t ioHandle) const = 0;
virtual int newAudioSessionId() = 0;
virtual void acquireAudioSessionId(int audioSession) = 0;
virtual void releaseAudioSessionId(int audioSession) = 0;
- virtual status_t queryNumberEffects(uint32_t *numEffects) = 0;
+ virtual status_t queryNumberEffects(uint32_t *numEffects) const = 0;
- virtual status_t queryEffect(uint32_t index, effect_descriptor_t *pDescriptor) = 0;
+ virtual status_t queryEffect(uint32_t index, effect_descriptor_t *pDescriptor) const = 0;
- virtual status_t getEffectDescriptor(effect_uuid_t *pEffectUUID, effect_descriptor_t *pDescriptor) = 0;
+ virtual status_t getEffectDescriptor(const effect_uuid_t *pEffectUUID,
+ effect_descriptor_t *pDescriptor) const = 0;
virtual sp<IEffect> createEffect(pid_t pid,
effect_descriptor_t *pDesc,
const sp<IEffectClient>& client,
int32_t priority,
- int output,
+ audio_io_handle_t output,
int sessionId,
status_t *status,
int *id,
int *enabled) = 0;
- virtual status_t moveEffects(int session, int srcOutput, int dstOutput) = 0;
+ virtual status_t moveEffects(int session, audio_io_handle_t srcOutput,
+ audio_io_handle_t dstOutput) = 0;
};
diff --git a/include/media/IAudioFlingerClient.h b/include/media/IAudioFlingerClient.h
index aa0cdcf..f3b4df1 100644
--- a/include/media/IAudioFlingerClient.h
+++ b/include/media/IAudioFlingerClient.h
@@ -21,6 +21,7 @@
#include <utils/RefBase.h>
#include <binder/IInterface.h>
#include <utils/KeyedVector.h>
+#include <system/audio.h>
namespace android {
@@ -32,7 +33,7 @@
DECLARE_META_INTERFACE(AudioFlingerClient);
// Notifies a change of audio input/output configuration.
- virtual void ioConfigChanged(int event, int ioHandle, void *param2) = 0;
+ virtual void ioConfigChanged(int event, audio_io_handle_t ioHandle, void *param2) = 0;
};
diff --git a/include/media/stagefright/MediaDebug.h b/include/media/stagefright/MediaDebug.h
deleted file mode 100644
index 2ca9667..0000000
--- a/include/media/stagefright/MediaDebug.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef MEDIA_DEBUG_H_
-
-#define MEDIA_DEBUG_H_
-
-#include <cutils/log.h>
-
-#define LITERAL_TO_STRING_INTERNAL(x) #x
-#define LITERAL_TO_STRING(x) LITERAL_TO_STRING_INTERNAL(x)
-
-#define CHECK_EQ(x,y) \
- LOG_ALWAYS_FATAL_IF( \
- (x) != (y), \
- __FILE__ ":" LITERAL_TO_STRING(__LINE__) " " #x " != " #y)
-
-#define CHECK(x) \
- LOG_ALWAYS_FATAL_IF( \
- !(x), \
- __FILE__ ":" LITERAL_TO_STRING(__LINE__) " " #x)
-
-#endif // MEDIA_DEBUG_H_
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 4c30e04..e541c18 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -335,7 +335,7 @@
status_t applyRotation();
status_t waitForBufferFilled_l();
- int64_t retrieveDecodingTimeUs(bool isCodecSpecific);
+ int64_t getDecodingTimeUs();
status_t parseAVCCodecSpecificData(
const void *data, size_t size,
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index dd97ce4..23226c0 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -54,6 +54,7 @@
#define CBLK_RESTORED_ON 0x0040 // track has been restored after invalidation
#define CBLK_RESTORED_OFF 0x0040 // by AudioFlinger
+// Important: do not add any virtual methods, including ~
struct audio_track_cblk_t
{
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 33b305d..1750640 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -151,12 +151,14 @@
return reply.readStrongBinder();
}
- virtual status_t addService(const String16& name, const sp<IBinder>& service)
+ virtual status_t addService(const String16& name, const sp<IBinder>& service,
+ bool allowIsolated)
{
Parcel data, reply;
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
data.writeString16(name);
data.writeStrongBinder(service);
+ data.writeInt32(allowIsolated ? 1 : 0);
status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
return err == NO_ERROR ? reply.readExceptionCode() : err;
}
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk
index b6f5b9e..2f4ac62 100644
--- a/libs/gui/Android.mk
+++ b/libs/gui/Android.mk
@@ -3,6 +3,7 @@
LOCAL_SRC_FILES:= \
BitTube.cpp \
+ BufferQueue.cpp \
DisplayEventReceiver.cpp \
IDisplayEventConnection.cpp \
ISensorEventConnection.cpp \
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
new file mode 100644
index 0000000..c7e2c0f
--- /dev/null
+++ b/libs/gui/BufferQueue.cpp
@@ -0,0 +1,722 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "BufferQueue"
+
+#define GL_GLEXT_PROTOTYPES
+#define EGL_EGLEXT_PROTOTYPES
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <gui/BufferQueue.h>
+#include <private/gui/ComposerService.h>
+#include <surfaceflinger/ISurfaceComposer.h>
+
+#include <utils/Log.h>
+
+// This compile option causes SurfaceTexture to return the buffer that is currently
+// attached to the GL texture from dequeueBuffer when no other buffers are
+// available. It requires the drivers (Gralloc, GL, OMX IL, and Camera) to do
+// implicit cross-process synchronization to prevent the buffer from being
+// written to before the buffer has (a) been detached from the GL texture and
+// (b) all GL reads from the buffer have completed.
+#ifdef ALLOW_DEQUEUE_CURRENT_BUFFER
+#define FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER true
+#warning "ALLOW_DEQUEUE_CURRENT_BUFFER enabled"
+#else
+#define FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER false
+#endif
+
+// Macros for including the BufferQueue name in log messages
+#define ST_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define ST_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define ST_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define ST_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define ST_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__)
+
+namespace android {
+
+// Get an ID that's unique within this process.
+static int32_t createProcessUniqueId() {
+ static volatile int32_t globalCounter = 0;
+ return android_atomic_inc(&globalCounter);
+}
+
+BufferQueue::BufferQueue( bool allowSynchronousMode ) :
+ mDefaultWidth(1),
+ mDefaultHeight(1),
+ mPixelFormat(PIXEL_FORMAT_RGBA_8888),
+ mBufferCount(MIN_ASYNC_BUFFER_SLOTS),
+ mClientBufferCount(0),
+ mServerBufferCount(MIN_ASYNC_BUFFER_SLOTS),
+ mCurrentTexture(INVALID_BUFFER_SLOT),
+ mNextTransform(0),
+ mNextScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
+ mSynchronousMode(false),
+ mAllowSynchronousMode(allowSynchronousMode),
+ mConnectedApi(NO_CONNECTED_API),
+ mAbandoned(false),
+ mFrameCounter(0)
+{
+ // Choose a name using the PID and a process-unique ID.
+ mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
+
+ ST_LOGV("BufferQueue");
+ sp<ISurfaceComposer> composer(ComposerService::getComposerService());
+ mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
+ mNextCrop.makeInvalid();
+}
+
+BufferQueue::~BufferQueue() {
+ ST_LOGV("~BufferQueue");
+}
+
+status_t BufferQueue::setBufferCountServerLocked(int bufferCount) {
+ if (bufferCount > NUM_BUFFER_SLOTS)
+ return BAD_VALUE;
+
+ // special-case, nothing to do
+ if (bufferCount == mBufferCount)
+ return OK;
+
+ if (!mClientBufferCount &&
+ bufferCount >= mBufferCount) {
+ // easy, we just have more buffers
+ mBufferCount = bufferCount;
+ mServerBufferCount = bufferCount;
+ mDequeueCondition.signal();
+ } else {
+ // we're here because we're either
+ // - reducing the number of available buffers
+ // - or there is a client-buffer-count in effect
+
+ // less than 2 buffers is never allowed
+ if (bufferCount < 2)
+ return BAD_VALUE;
+
+ // when there is non client-buffer-count in effect, the client is not
+ // allowed to dequeue more than one buffer at a time,
+ // so the next time they dequeue a buffer, we know that they don't
+ // own one. the actual resizing will happen during the next
+ // dequeueBuffer.
+
+ mServerBufferCount = bufferCount;
+ }
+ return OK;
+}
+
+status_t BufferQueue::setBufferCount(int bufferCount) {
+ ST_LOGV("setBufferCount: count=%d", bufferCount);
+ Mutex::Autolock lock(mMutex);
+
+ if (mAbandoned) {
+ ST_LOGE("setBufferCount: SurfaceTexture has been abandoned!");
+ return NO_INIT;
+ }
+ if (bufferCount > NUM_BUFFER_SLOTS) {
+ ST_LOGE("setBufferCount: bufferCount larger than slots available");
+ return BAD_VALUE;
+ }
+
+ // Error out if the user has dequeued buffers
+ for (int i=0 ; i<mBufferCount ; i++) {
+ if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) {
+ ST_LOGE("setBufferCount: client owns some buffers");
+ return -EINVAL;
+ }
+ }
+
+ const int minBufferSlots = mSynchronousMode ?
+ MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
+ if (bufferCount == 0) {
+ mClientBufferCount = 0;
+ bufferCount = (mServerBufferCount >= minBufferSlots) ?
+ mServerBufferCount : minBufferSlots;
+ return setBufferCountServerLocked(bufferCount);
+ }
+
+ if (bufferCount < minBufferSlots) {
+ ST_LOGE("setBufferCount: requested buffer count (%d) is less than "
+ "minimum (%d)", bufferCount, minBufferSlots);
+ return BAD_VALUE;
+ }
+
+ // here we're guaranteed that the client doesn't have dequeued buffers
+ // and will release all of its buffer references.
+ freeAllBuffersLocked();
+ mBufferCount = bufferCount;
+ mClientBufferCount = bufferCount;
+ mCurrentTexture = INVALID_BUFFER_SLOT;
+ mQueue.clear();
+ mDequeueCondition.signal();
+ return OK;
+}
+
+status_t BufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
+ ST_LOGV("requestBuffer: slot=%d", slot);
+ Mutex::Autolock lock(mMutex);
+ if (mAbandoned) {
+ ST_LOGE("requestBuffer: SurfaceTexture has been abandoned!");
+ return NO_INIT;
+ }
+ if (slot < 0 || mBufferCount <= slot) {
+ ST_LOGE("requestBuffer: slot index out of range [0, %d]: %d",
+ mBufferCount, slot);
+ return BAD_VALUE;
+ }
+ mSlots[slot].mRequestBufferCalled = true;
+ *buf = mSlots[slot].mGraphicBuffer;
+ return NO_ERROR;
+}
+
+status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
+ uint32_t format, uint32_t usage) {
+ ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage);
+
+ if ((w && !h) || (!w && h)) {
+ ST_LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h);
+ return BAD_VALUE;
+ }
+
+ status_t returnFlags(OK);
+ EGLDisplay dpy = EGL_NO_DISPLAY;
+ EGLSyncKHR fence = EGL_NO_SYNC_KHR;
+
+ { // Scope for the lock
+ Mutex::Autolock lock(mMutex);
+
+ int found = -1;
+ int foundSync = -1;
+ int dequeuedCount = 0;
+ bool tryAgain = true;
+ while (tryAgain) {
+ if (mAbandoned) {
+ ST_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!");
+ return NO_INIT;
+ }
+
+ // We need to wait for the FIFO to drain if the number of buffer
+ // needs to change.
+ //
+ // The condition "number of buffers needs to change" is true if
+ // - the client doesn't care about how many buffers there are
+ // - AND the actual number of buffer is different from what was
+ // set in the last setBufferCountServer()
+ // - OR -
+ // setBufferCountServer() was set to a value incompatible with
+ // the synchronization mode (for instance because the sync mode
+ // changed since)
+ //
+ // As long as this condition is true AND the FIFO is not empty, we
+ // wait on mDequeueCondition.
+
+ const int minBufferCountNeeded = mSynchronousMode ?
+ MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
+
+ const bool numberOfBuffersNeedsToChange = !mClientBufferCount &&
+ ((mServerBufferCount != mBufferCount) ||
+ (mServerBufferCount < minBufferCountNeeded));
+
+ if (!mQueue.isEmpty() && numberOfBuffersNeedsToChange) {
+ // wait for the FIFO to drain
+ mDequeueCondition.wait(mMutex);
+ // NOTE: we continue here because we need to reevaluate our
+ // whole state (eg: we could be abandoned or disconnected)
+ continue;
+ }
+
+ if (numberOfBuffersNeedsToChange) {
+ // here we're guaranteed that mQueue is empty
+ freeAllBuffersLocked();
+ mBufferCount = mServerBufferCount;
+ if (mBufferCount < minBufferCountNeeded)
+ mBufferCount = minBufferCountNeeded;
+ mCurrentTexture = INVALID_BUFFER_SLOT;
+ returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS;
+ }
+
+ // look for a free buffer to give to the client
+ found = INVALID_BUFFER_SLOT;
+ foundSync = INVALID_BUFFER_SLOT;
+ dequeuedCount = 0;
+ for (int i = 0; i < mBufferCount; i++) {
+ const int state = mSlots[i].mBufferState;
+ if (state == BufferSlot::DEQUEUED) {
+ dequeuedCount++;
+ }
+
+ // if buffer is FREE it CANNOT be current
+ ALOGW_IF((state == BufferSlot::FREE) && (mCurrentTexture==i),
+ "dequeueBuffer: buffer %d is both FREE and current!",
+ i);
+
+ if (FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER) {
+ if (state == BufferSlot::FREE || i == mCurrentTexture) {
+ foundSync = i;
+ if (i != mCurrentTexture) {
+ found = i;
+ break;
+ }
+ }
+ } else {
+ if (state == BufferSlot::FREE) {
+ /* We return the oldest of the free buffers to avoid
+ * stalling the producer if possible. This is because
+ * the consumer may still have pending reads of the
+ * buffers in flight.
+ */
+ bool isOlder = mSlots[i].mFrameNumber <
+ mSlots[found].mFrameNumber;
+ if (found < 0 || isOlder) {
+ foundSync = i;
+ found = i;
+ }
+ }
+ }
+ }
+
+ // clients are not allowed to dequeue more than one buffer
+ // if they didn't set a buffer count.
+ if (!mClientBufferCount && dequeuedCount) {
+ ST_LOGE("dequeueBuffer: can't dequeue multiple buffers without "
+ "setting the buffer count");
+ return -EINVAL;
+ }
+
+ // See whether a buffer has been queued since the last
+ // setBufferCount so we know whether to perform the
+ // MIN_UNDEQUEUED_BUFFERS check below.
+ bool bufferHasBeenQueued = mCurrentTexture != INVALID_BUFFER_SLOT;
+ if (bufferHasBeenQueued) {
+ // make sure the client is not trying to dequeue more buffers
+ // than allowed.
+ const int avail = mBufferCount - (dequeuedCount+1);
+ if (avail < (MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode))) {
+ ST_LOGE("dequeueBuffer: MIN_UNDEQUEUED_BUFFERS=%d exceeded "
+ "(dequeued=%d)",
+ MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode),
+ dequeuedCount);
+ return -EBUSY;
+ }
+ }
+
+ // we're in synchronous mode and didn't find a buffer, we need to
+ // wait for some buffers to be consumed
+ tryAgain = mSynchronousMode && (foundSync == INVALID_BUFFER_SLOT);
+ if (tryAgain) {
+ mDequeueCondition.wait(mMutex);
+ }
+ }
+
+ if (mSynchronousMode && found == INVALID_BUFFER_SLOT) {
+ // foundSync guaranteed to be != INVALID_BUFFER_SLOT
+ found = foundSync;
+ }
+
+ if (found == INVALID_BUFFER_SLOT) {
+ // This should not happen.
+ ST_LOGE("dequeueBuffer: no available buffer slots");
+ return -EBUSY;
+ }
+
+ const int buf = found;
+ *outBuf = found;
+
+ const bool useDefaultSize = !w && !h;
+ if (useDefaultSize) {
+ // use the default size
+ w = mDefaultWidth;
+ h = mDefaultHeight;
+ }
+
+ const bool updateFormat = (format != 0);
+ if (!updateFormat) {
+ // keep the current (or default) format
+ format = mPixelFormat;
+ }
+
+ // buffer is now in DEQUEUED (but can also be current at the same time,
+ // if we're in synchronous mode)
+ mSlots[buf].mBufferState = BufferSlot::DEQUEUED;
+
+ const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer);
+ if ((buffer == NULL) ||
+ (uint32_t(buffer->width) != w) ||
+ (uint32_t(buffer->height) != h) ||
+ (uint32_t(buffer->format) != format) ||
+ ((uint32_t(buffer->usage) & usage) != usage))
+ {
+ usage |= GraphicBuffer::USAGE_HW_TEXTURE;
+ status_t error;
+ sp<GraphicBuffer> graphicBuffer(
+ mGraphicBufferAlloc->createGraphicBuffer(
+ w, h, format, usage, &error));
+ if (graphicBuffer == 0) {
+ ST_LOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer "
+ "failed");
+ return error;
+ }
+ if (updateFormat) {
+ mPixelFormat = format;
+ }
+ mSlots[buf].mGraphicBuffer = graphicBuffer;
+ mSlots[buf].mRequestBufferCalled = false;
+ mSlots[buf].mFence = EGL_NO_SYNC_KHR;
+ if (mSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) {
+ eglDestroyImageKHR(mSlots[buf].mEglDisplay,
+ mSlots[buf].mEglImage);
+ mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR;
+ mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
+ }
+ if (mCurrentTexture == buf) {
+ // The current texture no longer references the buffer in this slot
+ // since we just allocated a new buffer.
+ mCurrentTexture = INVALID_BUFFER_SLOT;
+ }
+ returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;
+ }
+
+ dpy = mSlots[buf].mEglDisplay;
+ fence = mSlots[buf].mFence;
+ mSlots[buf].mFence = EGL_NO_SYNC_KHR;
+ }
+
+ if (fence != EGL_NO_SYNC_KHR) {
+ EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000);
+ // If something goes wrong, log the error, but return the buffer without
+ // synchronizing access to it. It's too late at this point to abort the
+ // dequeue operation.
+ if (result == EGL_FALSE) {
+ ALOGE("dequeueBuffer: error waiting for fence: %#x", eglGetError());
+ } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
+ ALOGE("dequeueBuffer: timeout waiting for fence");
+ }
+ eglDestroySyncKHR(dpy, fence);
+ }
+
+ ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", *outBuf,
+ mSlots[*outBuf].mGraphicBuffer->handle, returnFlags);
+
+ return returnFlags;
+}
+
+status_t BufferQueue::setSynchronousMode(bool enabled) {
+ ST_LOGV("setSynchronousMode: enabled=%d", enabled);
+ Mutex::Autolock lock(mMutex);
+
+ if (mAbandoned) {
+ ST_LOGE("setSynchronousMode: SurfaceTexture has been abandoned!");
+ return NO_INIT;
+ }
+
+ status_t err = OK;
+ if (!mAllowSynchronousMode && enabled)
+ return err;
+
+ if (!enabled) {
+ // going to asynchronous mode, drain the queue
+ err = drainQueueLocked();
+ if (err != NO_ERROR)
+ return err;
+ }
+
+ if (mSynchronousMode != enabled) {
+ // - if we're going to asynchronous mode, the queue is guaranteed to be
+ // empty here
+ // - if the client set the number of buffers, we're guaranteed that
+ // we have at least 3 (because we don't allow less)
+ mSynchronousMode = enabled;
+ mDequeueCondition.signal();
+ }
+ return err;
+}
+
+status_t BufferQueue::queueBuffer(int buf, int64_t timestamp,
+ uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
+ ST_LOGV("queueBuffer: slot=%d time=%lld", buf, timestamp);
+
+ sp<FrameAvailableListener> listener;
+
+ { // scope for the lock
+ Mutex::Autolock lock(mMutex);
+ if (mAbandoned) {
+ ST_LOGE("queueBuffer: SurfaceTexture has been abandoned!");
+ return NO_INIT;
+ }
+ if (buf < 0 || buf >= mBufferCount) {
+ ST_LOGE("queueBuffer: slot index out of range [0, %d]: %d",
+ mBufferCount, buf);
+ return -EINVAL;
+ } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
+ ST_LOGE("queueBuffer: slot %d is not owned by the client "
+ "(state=%d)", buf, mSlots[buf].mBufferState);
+ return -EINVAL;
+ } else if (buf == mCurrentTexture) {
+ ST_LOGE("queueBuffer: slot %d is current!", buf);
+ return -EINVAL;
+ } else if (!mSlots[buf].mRequestBufferCalled) {
+ ST_LOGE("queueBuffer: slot %d was enqueued without requesting a "
+ "buffer", buf);
+ return -EINVAL;
+ }
+
+ if (mSynchronousMode) {
+ // In synchronous mode we queue all buffers in a FIFO.
+ mQueue.push_back(buf);
+
+ // Synchronous mode always signals that an additional frame should
+ // be consumed.
+ listener = mFrameAvailableListener;
+ } else {
+ // In asynchronous mode we only keep the most recent buffer.
+ if (mQueue.empty()) {
+ mQueue.push_back(buf);
+
+ // Asynchronous mode only signals that a frame should be
+ // consumed if no previous frame was pending. If a frame were
+ // pending then the consumer would have already been notified.
+ listener = mFrameAvailableListener;
+ } else {
+ Fifo::iterator front(mQueue.begin());
+ // buffer currently queued is freed
+ mSlots[*front].mBufferState = BufferSlot::FREE;
+ // and we record the new buffer index in the queued list
+ *front = buf;
+ }
+ }
+
+ mSlots[buf].mBufferState = BufferSlot::QUEUED;
+ mSlots[buf].mCrop = mNextCrop;
+ mSlots[buf].mTransform = mNextTransform;
+ mSlots[buf].mScalingMode = mNextScalingMode;
+ mSlots[buf].mTimestamp = timestamp;
+ mFrameCounter++;
+ mSlots[buf].mFrameNumber = mFrameCounter;
+
+ mDequeueCondition.signal();
+
+ *outWidth = mDefaultWidth;
+ *outHeight = mDefaultHeight;
+ *outTransform = 0;
+ } // scope for the lock
+
+ // call back without lock held
+ if (listener != 0) {
+ listener->onFrameAvailable();
+ }
+ return OK;
+}
+
+void BufferQueue::cancelBuffer(int buf) {
+ ST_LOGV("cancelBuffer: slot=%d", buf);
+ Mutex::Autolock lock(mMutex);
+
+ if (mAbandoned) {
+ ST_LOGW("cancelBuffer: BufferQueue has been abandoned!");
+ return;
+ }
+
+ if (buf < 0 || buf >= mBufferCount) {
+ ST_LOGE("cancelBuffer: slot index out of range [0, %d]: %d",
+ mBufferCount, buf);
+ return;
+ } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
+ ST_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)",
+ buf, mSlots[buf].mBufferState);
+ return;
+ }
+ mSlots[buf].mBufferState = BufferSlot::FREE;
+ mSlots[buf].mFrameNumber = 0;
+ mDequeueCondition.signal();
+}
+
+status_t BufferQueue::setCrop(const Rect& crop) {
+ ST_LOGV("setCrop: crop=[%d,%d,%d,%d]", crop.left, crop.top, crop.right,
+ crop.bottom);
+
+ Mutex::Autolock lock(mMutex);
+ if (mAbandoned) {
+ ST_LOGE("setCrop: BufferQueue has been abandoned!");
+ return NO_INIT;
+ }
+ mNextCrop = crop;
+ return OK;
+}
+
+status_t BufferQueue::setTransform(uint32_t transform) {
+ ST_LOGV("setTransform: xform=%#x", transform);
+ Mutex::Autolock lock(mMutex);
+ if (mAbandoned) {
+ ST_LOGE("setTransform: BufferQueue has been abandoned!");
+ return NO_INIT;
+ }
+ mNextTransform = transform;
+ return OK;
+}
+
+status_t BufferQueue::setScalingMode(int mode) {
+ ST_LOGV("setScalingMode: mode=%d", mode);
+
+ switch (mode) {
+ case NATIVE_WINDOW_SCALING_MODE_FREEZE:
+ case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
+ break;
+ default:
+ ST_LOGE("unknown scaling mode: %d", mode);
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock lock(mMutex);
+ mNextScalingMode = mode;
+ return OK;
+}
+
+status_t BufferQueue::connect(int api,
+ uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
+ ST_LOGV("connect: api=%d", api);
+ Mutex::Autolock lock(mMutex);
+
+ if (mAbandoned) {
+ ST_LOGE("connect: BufferQueue has been abandoned!");
+ return NO_INIT;
+ }
+
+ int err = NO_ERROR;
+ switch (api) {
+ case NATIVE_WINDOW_API_EGL:
+ case NATIVE_WINDOW_API_CPU:
+ case NATIVE_WINDOW_API_MEDIA:
+ case NATIVE_WINDOW_API_CAMERA:
+ if (mConnectedApi != NO_CONNECTED_API) {
+ ST_LOGE("connect: already connected (cur=%d, req=%d)",
+ mConnectedApi, api);
+ err = -EINVAL;
+ } else {
+ mConnectedApi = api;
+ *outWidth = mDefaultWidth;
+ *outHeight = mDefaultHeight;
+ *outTransform = 0;
+ }
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+ return err;
+}
+
+status_t BufferQueue::disconnect(int api) {
+ ST_LOGV("disconnect: api=%d", api);
+ Mutex::Autolock lock(mMutex);
+
+ if (mAbandoned) {
+ // it is not really an error to disconnect after the surface
+ // has been abandoned, it should just be a no-op.
+ return NO_ERROR;
+ }
+
+ int err = NO_ERROR;
+ switch (api) {
+ case NATIVE_WINDOW_API_EGL:
+ case NATIVE_WINDOW_API_CPU:
+ case NATIVE_WINDOW_API_MEDIA:
+ case NATIVE_WINDOW_API_CAMERA:
+ if (mConnectedApi == api) {
+ drainQueueAndFreeBuffersLocked();
+ mConnectedApi = NO_CONNECTED_API;
+ mNextCrop.makeInvalid();
+ mNextScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
+ mNextTransform = 0;
+ mDequeueCondition.signal();
+ } else {
+ ST_LOGE("disconnect: connected to another api (cur=%d, req=%d)",
+ mConnectedApi, api);
+ err = -EINVAL;
+ }
+ break;
+ default:
+ ST_LOGE("disconnect: unknown API %d", api);
+ err = -EINVAL;
+ break;
+ }
+ return err;
+}
+
+void BufferQueue::freeBufferLocked(int i) {
+ mSlots[i].mGraphicBuffer = 0;
+ mSlots[i].mBufferState = BufferSlot::FREE;
+ mSlots[i].mFrameNumber = 0;
+ if (mSlots[i].mEglImage != EGL_NO_IMAGE_KHR) {
+ eglDestroyImageKHR(mSlots[i].mEglDisplay, mSlots[i].mEglImage);
+ mSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
+ mSlots[i].mEglDisplay = EGL_NO_DISPLAY;
+ }
+}
+
+void BufferQueue::freeAllBuffersLocked() {
+ ALOGW_IF(!mQueue.isEmpty(),
+ "freeAllBuffersLocked called but mQueue is not empty");
+ mCurrentTexture = INVALID_BUFFER_SLOT;
+ for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+ freeBufferLocked(i);
+ }
+}
+
+void BufferQueue::freeAllBuffersExceptHeadLocked() {
+ ALOGW_IF(!mQueue.isEmpty(),
+ "freeAllBuffersExceptCurrentLocked called but mQueue is not empty");
+ int head = -1;
+ if (!mQueue.empty()) {
+ Fifo::iterator front(mQueue.begin());
+ head = *front;
+ }
+ mCurrentTexture = INVALID_BUFFER_SLOT;
+ for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+ if (i != head) {
+ freeBufferLocked(i);
+ }
+ }
+}
+
+status_t BufferQueue::drainQueueLocked() {
+ while (mSynchronousMode && !mQueue.isEmpty()) {
+ mDequeueCondition.wait(mMutex);
+ if (mAbandoned) {
+ ST_LOGE("drainQueueLocked: BufferQueue has been abandoned!");
+ return NO_INIT;
+ }
+ if (mConnectedApi == NO_CONNECTED_API) {
+ ST_LOGE("drainQueueLocked: BufferQueue is not connected!");
+ return NO_INIT;
+ }
+ }
+ return NO_ERROR;
+}
+
+status_t BufferQueue::drainQueueAndFreeBuffersLocked() {
+ status_t err = drainQueueLocked();
+ if (err == NO_ERROR) {
+ if (mSynchronousMode) {
+ freeAllBuffersLocked();
+ } else {
+ freeAllBuffersExceptHeadLocked();
+ }
+ }
+ return err;
+}
+
+}; // namespace android
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 3abe84a..be1bcd1 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -38,19 +38,6 @@
#include <utils/Log.h>
#include <utils/String8.h>
-// This compile option causes SurfaceTexture to return the buffer that is currently
-// attached to the GL texture from dequeueBuffer when no other buffers are
-// available. It requires the drivers (Gralloc, GL, OMX IL, and Camera) to do
-// implicit cross-process synchronization to prevent the buffer from being
-// written to before the buffer has (a) been detached from the GL texture and
-// (b) all GL reads from the buffer have completed.
-#ifdef ALLOW_DEQUEUE_CURRENT_BUFFER
-#define FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER true
-#warning "ALLOW_DEQUEUE_CURRENT_BUFFER enabled"
-#else
-#define FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER false
-#endif
-
// This compile option makes SurfaceTexture use the EGL_KHR_fence_sync extension
// to synchronize access to the buffers. It will cause dequeueBuffer to stall,
// waiting for the GL reads for the buffer being dequeued to complete before
@@ -110,44 +97,22 @@
static void mtxMul(float out[16], const float a[16], const float b[16]);
-// Get an ID that's unique within this process.
-static int32_t createProcessUniqueId() {
- static volatile int32_t globalCounter = 0;
- return android_atomic_inc(&globalCounter);
-}
SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode,
GLenum texTarget, bool useFenceSync) :
- mDefaultWidth(1),
- mDefaultHeight(1),
- mPixelFormat(PIXEL_FORMAT_RGBA_8888),
- mBufferCount(MIN_ASYNC_BUFFER_SLOTS),
- mClientBufferCount(0),
- mServerBufferCount(MIN_ASYNC_BUFFER_SLOTS),
- mCurrentTexture(INVALID_BUFFER_SLOT),
+ BufferQueue(allowSynchronousMode),
mCurrentTransform(0),
mCurrentTimestamp(0),
- mNextTransform(0),
- mNextScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
mTexName(tex),
- mSynchronousMode(false),
- mAllowSynchronousMode(allowSynchronousMode),
- mConnectedApi(NO_CONNECTED_API),
- mAbandoned(false),
#ifdef USE_FENCE_SYNC
mUseFenceSync(useFenceSync),
#else
mUseFenceSync(false),
#endif
- mTexTarget(texTarget),
- mFrameCounter(0) {
- // Choose a name using the PID and a process-unique ID.
- mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
+ mTexTarget(texTarget)
+{
ST_LOGV("SurfaceTexture");
- sp<ISurfaceComposer> composer(ComposerService::getComposerService());
- mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
- mNextCrop.makeInvalid();
memcpy(mCurrentTransformMatrix, mtxIdentity,
sizeof(mCurrentTransformMatrix));
}
@@ -157,91 +122,11 @@
freeAllBuffersLocked();
}
-status_t SurfaceTexture::setBufferCountServerLocked(int bufferCount) {
- if (bufferCount > NUM_BUFFER_SLOTS)
- return BAD_VALUE;
-
- // special-case, nothing to do
- if (bufferCount == mBufferCount)
- return OK;
-
- if (!mClientBufferCount &&
- bufferCount >= mBufferCount) {
- // easy, we just have more buffers
- mBufferCount = bufferCount;
- mServerBufferCount = bufferCount;
- mDequeueCondition.signal();
- } else {
- // we're here because we're either
- // - reducing the number of available buffers
- // - or there is a client-buffer-count in effect
-
- // less than 2 buffers is never allowed
- if (bufferCount < 2)
- return BAD_VALUE;
-
- // when there is non client-buffer-count in effect, the client is not
- // allowed to dequeue more than one buffer at a time,
- // so the next time they dequeue a buffer, we know that they don't
- // own one. the actual resizing will happen during the next
- // dequeueBuffer.
-
- mServerBufferCount = bufferCount;
- }
- return OK;
-}
-
status_t SurfaceTexture::setBufferCountServer(int bufferCount) {
Mutex::Autolock lock(mMutex);
return setBufferCountServerLocked(bufferCount);
}
-status_t SurfaceTexture::setBufferCount(int bufferCount) {
- ST_LOGV("setBufferCount: count=%d", bufferCount);
- Mutex::Autolock lock(mMutex);
-
- if (mAbandoned) {
- ST_LOGE("setBufferCount: SurfaceTexture has been abandoned!");
- return NO_INIT;
- }
- if (bufferCount > NUM_BUFFER_SLOTS) {
- ST_LOGE("setBufferCount: bufferCount larger than slots available");
- return BAD_VALUE;
- }
-
- // Error out if the user has dequeued buffers
- for (int i=0 ; i<mBufferCount ; i++) {
- if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) {
- ST_LOGE("setBufferCount: client owns some buffers");
- return -EINVAL;
- }
- }
-
- const int minBufferSlots = mSynchronousMode ?
- MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
- if (bufferCount == 0) {
- mClientBufferCount = 0;
- bufferCount = (mServerBufferCount >= minBufferSlots) ?
- mServerBufferCount : minBufferSlots;
- return setBufferCountServerLocked(bufferCount);
- }
-
- if (bufferCount < minBufferSlots) {
- ST_LOGE("setBufferCount: requested buffer count (%d) is less than "
- "minimum (%d)", bufferCount, minBufferSlots);
- return BAD_VALUE;
- }
-
- // here we're guaranteed that the client doesn't have dequeued buffers
- // and will release all of its buffer references.
- freeAllBuffersLocked();
- mBufferCount = bufferCount;
- mClientBufferCount = bufferCount;
- mCurrentTexture = INVALID_BUFFER_SLOT;
- mQueue.clear();
- mDequeueCondition.signal();
- return OK;
-}
status_t SurfaceTexture::setDefaultBufferSize(uint32_t w, uint32_t h)
{
@@ -258,496 +143,6 @@
return OK;
}
-status_t SurfaceTexture::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
- ST_LOGV("requestBuffer: slot=%d", slot);
- Mutex::Autolock lock(mMutex);
- if (mAbandoned) {
- ST_LOGE("requestBuffer: SurfaceTexture has been abandoned!");
- return NO_INIT;
- }
- if (slot < 0 || mBufferCount <= slot) {
- ST_LOGE("requestBuffer: slot index out of range [0, %d]: %d",
- mBufferCount, slot);
- return BAD_VALUE;
- }
- mSlots[slot].mRequestBufferCalled = true;
- *buf = mSlots[slot].mGraphicBuffer;
- return NO_ERROR;
-}
-
-status_t SurfaceTexture::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
- uint32_t format, uint32_t usage) {
- ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage);
-
- if ((w && !h) || (!w && h)) {
- ST_LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h);
- return BAD_VALUE;
- }
-
- status_t returnFlags(OK);
- EGLDisplay dpy = EGL_NO_DISPLAY;
- EGLSyncKHR fence = EGL_NO_SYNC_KHR;
-
- { // Scope for the lock
- Mutex::Autolock lock(mMutex);
-
- int found = -1;
- int foundSync = -1;
- int dequeuedCount = 0;
- bool tryAgain = true;
- while (tryAgain) {
- if (mAbandoned) {
- ST_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!");
- return NO_INIT;
- }
-
- // We need to wait for the FIFO to drain if the number of buffer
- // needs to change.
- //
- // The condition "number of buffers needs to change" is true if
- // - the client doesn't care about how many buffers there are
- // - AND the actual number of buffer is different from what was
- // set in the last setBufferCountServer()
- // - OR -
- // setBufferCountServer() was set to a value incompatible with
- // the synchronization mode (for instance because the sync mode
- // changed since)
- //
- // As long as this condition is true AND the FIFO is not empty, we
- // wait on mDequeueCondition.
-
- const int minBufferCountNeeded = mSynchronousMode ?
- MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
-
- const bool numberOfBuffersNeedsToChange = !mClientBufferCount &&
- ((mServerBufferCount != mBufferCount) ||
- (mServerBufferCount < minBufferCountNeeded));
-
- if (!mQueue.isEmpty() && numberOfBuffersNeedsToChange) {
- // wait for the FIFO to drain
- mDequeueCondition.wait(mMutex);
- // NOTE: we continue here because we need to reevaluate our
- // whole state (eg: we could be abandoned or disconnected)
- continue;
- }
-
- if (numberOfBuffersNeedsToChange) {
- // here we're guaranteed that mQueue is empty
- freeAllBuffersLocked();
- mBufferCount = mServerBufferCount;
- if (mBufferCount < minBufferCountNeeded)
- mBufferCount = minBufferCountNeeded;
- mCurrentTexture = INVALID_BUFFER_SLOT;
- returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS;
- }
-
- // look for a free buffer to give to the client
- found = INVALID_BUFFER_SLOT;
- foundSync = INVALID_BUFFER_SLOT;
- dequeuedCount = 0;
- for (int i = 0; i < mBufferCount; i++) {
- const int state = mSlots[i].mBufferState;
- if (state == BufferSlot::DEQUEUED) {
- dequeuedCount++;
- }
-
- // if buffer is FREE it CANNOT be current
- ALOGW_IF((state == BufferSlot::FREE) && (mCurrentTexture==i),
- "dequeueBuffer: buffer %d is both FREE and current!",
- i);
-
- if (FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER) {
- if (state == BufferSlot::FREE || i == mCurrentTexture) {
- foundSync = i;
- if (i != mCurrentTexture) {
- found = i;
- break;
- }
- }
- } else {
- if (state == BufferSlot::FREE) {
- /* We return the oldest of the free buffers to avoid
- * stalling the producer if possible. This is because
- * the consumer may still have pending reads of the
- * buffers in flight.
- */
- bool isOlder = mSlots[i].mFrameNumber <
- mSlots[found].mFrameNumber;
- if (found < 0 || isOlder) {
- foundSync = i;
- found = i;
- }
- }
- }
- }
-
- // clients are not allowed to dequeue more than one buffer
- // if they didn't set a buffer count.
- if (!mClientBufferCount && dequeuedCount) {
- ST_LOGE("dequeueBuffer: can't dequeue multiple buffers without "
- "setting the buffer count");
- return -EINVAL;
- }
-
- // See whether a buffer has been queued since the last
- // setBufferCount so we know whether to perform the
- // MIN_UNDEQUEUED_BUFFERS check below.
- bool bufferHasBeenQueued = mCurrentTexture != INVALID_BUFFER_SLOT;
- if (bufferHasBeenQueued) {
- // make sure the client is not trying to dequeue more buffers
- // than allowed.
- const int avail = mBufferCount - (dequeuedCount+1);
- if (avail < (MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode))) {
- ST_LOGE("dequeueBuffer: MIN_UNDEQUEUED_BUFFERS=%d exceeded "
- "(dequeued=%d)",
- MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode),
- dequeuedCount);
- return -EBUSY;
- }
- }
-
- // we're in synchronous mode and didn't find a buffer, we need to
- // wait for some buffers to be consumed
- tryAgain = mSynchronousMode && (foundSync == INVALID_BUFFER_SLOT);
- if (tryAgain) {
- mDequeueCondition.wait(mMutex);
- }
- }
-
- if (mSynchronousMode && found == INVALID_BUFFER_SLOT) {
- // foundSync guaranteed to be != INVALID_BUFFER_SLOT
- found = foundSync;
- }
-
- if (found == INVALID_BUFFER_SLOT) {
- // This should not happen.
- ST_LOGE("dequeueBuffer: no available buffer slots");
- return -EBUSY;
- }
-
- const int buf = found;
- *outBuf = found;
-
- const bool useDefaultSize = !w && !h;
- if (useDefaultSize) {
- // use the default size
- w = mDefaultWidth;
- h = mDefaultHeight;
- }
-
- const bool updateFormat = (format != 0);
- if (!updateFormat) {
- // keep the current (or default) format
- format = mPixelFormat;
- }
-
- // buffer is now in DEQUEUED (but can also be current at the same time,
- // if we're in synchronous mode)
- mSlots[buf].mBufferState = BufferSlot::DEQUEUED;
-
- const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer);
- if ((buffer == NULL) ||
- (uint32_t(buffer->width) != w) ||
- (uint32_t(buffer->height) != h) ||
- (uint32_t(buffer->format) != format) ||
- ((uint32_t(buffer->usage) & usage) != usage))
- {
- usage |= GraphicBuffer::USAGE_HW_TEXTURE;
- status_t error;
- sp<GraphicBuffer> graphicBuffer(
- mGraphicBufferAlloc->createGraphicBuffer(
- w, h, format, usage, &error));
- if (graphicBuffer == 0) {
- ST_LOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer "
- "failed");
- return error;
- }
- if (updateFormat) {
- mPixelFormat = format;
- }
- mSlots[buf].mGraphicBuffer = graphicBuffer;
- mSlots[buf].mRequestBufferCalled = false;
- mSlots[buf].mFence = EGL_NO_SYNC_KHR;
- if (mSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) {
- eglDestroyImageKHR(mSlots[buf].mEglDisplay,
- mSlots[buf].mEglImage);
- mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR;
- mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
- }
- if (mCurrentTexture == buf) {
- // The current texture no longer references the buffer in this slot
- // since we just allocated a new buffer.
- mCurrentTexture = INVALID_BUFFER_SLOT;
- }
- returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;
- }
-
- dpy = mSlots[buf].mEglDisplay;
- fence = mSlots[buf].mFence;
- mSlots[buf].mFence = EGL_NO_SYNC_KHR;
- }
-
- if (fence != EGL_NO_SYNC_KHR) {
- EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000);
- // If something goes wrong, log the error, but return the buffer without
- // synchronizing access to it. It's too late at this point to abort the
- // dequeue operation.
- if (result == EGL_FALSE) {
- ALOGE("dequeueBuffer: error waiting for fence: %#x", eglGetError());
- } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
- ALOGE("dequeueBuffer: timeout waiting for fence");
- }
- eglDestroySyncKHR(dpy, fence);
- }
-
- ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", *outBuf,
- mSlots[*outBuf].mGraphicBuffer->handle, returnFlags);
-
- return returnFlags;
-}
-
-status_t SurfaceTexture::setSynchronousMode(bool enabled) {
- ST_LOGV("setSynchronousMode: enabled=%d", enabled);
- Mutex::Autolock lock(mMutex);
-
- if (mAbandoned) {
- ST_LOGE("setSynchronousMode: SurfaceTexture has been abandoned!");
- return NO_INIT;
- }
-
- status_t err = OK;
- if (!mAllowSynchronousMode && enabled)
- return err;
-
- if (!enabled) {
- // going to asynchronous mode, drain the queue
- err = drainQueueLocked();
- if (err != NO_ERROR)
- return err;
- }
-
- if (mSynchronousMode != enabled) {
- // - if we're going to asynchronous mode, the queue is guaranteed to be
- // empty here
- // - if the client set the number of buffers, we're guaranteed that
- // we have at least 3 (because we don't allow less)
- mSynchronousMode = enabled;
- mDequeueCondition.signal();
- }
- return err;
-}
-
-status_t SurfaceTexture::queueBuffer(int buf, int64_t timestamp,
- uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
- ST_LOGV("queueBuffer: slot=%d time=%lld", buf, timestamp);
-
- sp<FrameAvailableListener> listener;
-
- { // scope for the lock
- Mutex::Autolock lock(mMutex);
- if (mAbandoned) {
- ST_LOGE("queueBuffer: SurfaceTexture has been abandoned!");
- return NO_INIT;
- }
- if (buf < 0 || buf >= mBufferCount) {
- ST_LOGE("queueBuffer: slot index out of range [0, %d]: %d",
- mBufferCount, buf);
- return -EINVAL;
- } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
- ST_LOGE("queueBuffer: slot %d is not owned by the client "
- "(state=%d)", buf, mSlots[buf].mBufferState);
- return -EINVAL;
- } else if (buf == mCurrentTexture) {
- ST_LOGE("queueBuffer: slot %d is current!", buf);
- return -EINVAL;
- } else if (!mSlots[buf].mRequestBufferCalled) {
- ST_LOGE("queueBuffer: slot %d was enqueued without requesting a "
- "buffer", buf);
- return -EINVAL;
- }
-
- if (mSynchronousMode) {
- // In synchronous mode we queue all buffers in a FIFO.
- mQueue.push_back(buf);
-
- // Synchronous mode always signals that an additional frame should
- // be consumed.
- listener = mFrameAvailableListener;
- } else {
- // In asynchronous mode we only keep the most recent buffer.
- if (mQueue.empty()) {
- mQueue.push_back(buf);
-
- // Asynchronous mode only signals that a frame should be
- // consumed if no previous frame was pending. If a frame were
- // pending then the consumer would have already been notified.
- listener = mFrameAvailableListener;
- } else {
- Fifo::iterator front(mQueue.begin());
- // buffer currently queued is freed
- mSlots[*front].mBufferState = BufferSlot::FREE;
- // and we record the new buffer index in the queued list
- *front = buf;
- }
- }
-
- mSlots[buf].mBufferState = BufferSlot::QUEUED;
- mSlots[buf].mCrop = mNextCrop;
- mSlots[buf].mTransform = mNextTransform;
- mSlots[buf].mScalingMode = mNextScalingMode;
- mSlots[buf].mTimestamp = timestamp;
- mFrameCounter++;
- mSlots[buf].mFrameNumber = mFrameCounter;
-
- mDequeueCondition.signal();
-
- *outWidth = mDefaultWidth;
- *outHeight = mDefaultHeight;
- *outTransform = 0;
- } // scope for the lock
-
- // call back without lock held
- if (listener != 0) {
- listener->onFrameAvailable();
- }
- return OK;
-}
-
-void SurfaceTexture::cancelBuffer(int buf) {
- ST_LOGV("cancelBuffer: slot=%d", buf);
- Mutex::Autolock lock(mMutex);
-
- if (mAbandoned) {
- ST_LOGW("cancelBuffer: SurfaceTexture has been abandoned!");
- return;
- }
-
- if (buf < 0 || buf >= mBufferCount) {
- ST_LOGE("cancelBuffer: slot index out of range [0, %d]: %d",
- mBufferCount, buf);
- return;
- } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
- ST_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)",
- buf, mSlots[buf].mBufferState);
- return;
- }
- mSlots[buf].mBufferState = BufferSlot::FREE;
- mSlots[buf].mFrameNumber = 0;
- mDequeueCondition.signal();
-}
-
-status_t SurfaceTexture::setCrop(const Rect& crop) {
- ST_LOGV("setCrop: crop=[%d,%d,%d,%d]", crop.left, crop.top, crop.right,
- crop.bottom);
-
- Mutex::Autolock lock(mMutex);
- if (mAbandoned) {
- ST_LOGE("setCrop: SurfaceTexture has been abandoned!");
- return NO_INIT;
- }
- mNextCrop = crop;
- return OK;
-}
-
-status_t SurfaceTexture::setTransform(uint32_t transform) {
- ST_LOGV("setTransform: xform=%#x", transform);
- Mutex::Autolock lock(mMutex);
- if (mAbandoned) {
- ST_LOGE("setTransform: SurfaceTexture has been abandoned!");
- return NO_INIT;
- }
- mNextTransform = transform;
- return OK;
-}
-
-status_t SurfaceTexture::connect(int api,
- uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
- ST_LOGV("connect: api=%d", api);
- Mutex::Autolock lock(mMutex);
-
- if (mAbandoned) {
- ST_LOGE("connect: SurfaceTexture has been abandoned!");
- return NO_INIT;
- }
-
- int err = NO_ERROR;
- switch (api) {
- case NATIVE_WINDOW_API_EGL:
- case NATIVE_WINDOW_API_CPU:
- case NATIVE_WINDOW_API_MEDIA:
- case NATIVE_WINDOW_API_CAMERA:
- if (mConnectedApi != NO_CONNECTED_API) {
- ST_LOGE("connect: already connected (cur=%d, req=%d)",
- mConnectedApi, api);
- err = -EINVAL;
- } else {
- mConnectedApi = api;
- *outWidth = mDefaultWidth;
- *outHeight = mDefaultHeight;
- *outTransform = 0;
- }
- break;
- default:
- err = -EINVAL;
- break;
- }
- return err;
-}
-
-status_t SurfaceTexture::disconnect(int api) {
- ST_LOGV("disconnect: api=%d", api);
- Mutex::Autolock lock(mMutex);
-
- if (mAbandoned) {
- // it is not really an error to disconnect after the surface
- // has been abandoned, it should just be a no-op.
- return NO_ERROR;
- }
-
- int err = NO_ERROR;
- switch (api) {
- case NATIVE_WINDOW_API_EGL:
- case NATIVE_WINDOW_API_CPU:
- case NATIVE_WINDOW_API_MEDIA:
- case NATIVE_WINDOW_API_CAMERA:
- if (mConnectedApi == api) {
- drainQueueAndFreeBuffersLocked();
- mConnectedApi = NO_CONNECTED_API;
- mNextCrop.makeInvalid();
- mNextScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
- mNextTransform = 0;
- mDequeueCondition.signal();
- } else {
- ST_LOGE("disconnect: connected to another api (cur=%d, req=%d)",
- mConnectedApi, api);
- err = -EINVAL;
- }
- break;
- default:
- ST_LOGE("disconnect: unknown API %d", api);
- err = -EINVAL;
- break;
- }
- return err;
-}
-
-status_t SurfaceTexture::setScalingMode(int mode) {
- ST_LOGV("setScalingMode: mode=%d", mode);
-
- switch (mode) {
- case NATIVE_WINDOW_SCALING_MODE_FREEZE:
- case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
- break;
- default:
- ST_LOGE("unknown scaling mode: %d", mode);
- return BAD_VALUE;
- }
-
- Mutex::Autolock lock(mMutex);
- mNextScalingMode = mode;
- return OK;
-}
-
status_t SurfaceTexture::updateTexImage() {
ST_LOGV("updateTexImage");
Mutex::Autolock lock(mMutex);
@@ -980,69 +375,6 @@
mFrameAvailableListener = listener;
}
-void SurfaceTexture::freeBufferLocked(int i) {
- mSlots[i].mGraphicBuffer = 0;
- mSlots[i].mBufferState = BufferSlot::FREE;
- mSlots[i].mFrameNumber = 0;
- if (mSlots[i].mEglImage != EGL_NO_IMAGE_KHR) {
- eglDestroyImageKHR(mSlots[i].mEglDisplay, mSlots[i].mEglImage);
- mSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
- mSlots[i].mEglDisplay = EGL_NO_DISPLAY;
- }
-}
-
-void SurfaceTexture::freeAllBuffersLocked() {
- ALOGW_IF(!mQueue.isEmpty(),
- "freeAllBuffersLocked called but mQueue is not empty");
- mCurrentTexture = INVALID_BUFFER_SLOT;
- for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
- freeBufferLocked(i);
- }
-}
-
-void SurfaceTexture::freeAllBuffersExceptHeadLocked() {
- ALOGW_IF(!mQueue.isEmpty(),
- "freeAllBuffersExceptCurrentLocked called but mQueue is not empty");
- int head = -1;
- if (!mQueue.empty()) {
- Fifo::iterator front(mQueue.begin());
- head = *front;
- }
- mCurrentTexture = INVALID_BUFFER_SLOT;
- for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
- if (i != head) {
- freeBufferLocked(i);
- }
- }
-}
-
-status_t SurfaceTexture::drainQueueLocked() {
- while (mSynchronousMode && !mQueue.isEmpty()) {
- mDequeueCondition.wait(mMutex);
- if (mAbandoned) {
- ST_LOGE("drainQueueLocked: SurfaceTexture has been abandoned!");
- return NO_INIT;
- }
- if (mConnectedApi == NO_CONNECTED_API) {
- ST_LOGE("drainQueueLocked: SurfaceTexture is not connected!");
- return NO_INIT;
- }
- }
- return NO_ERROR;
-}
-
-status_t SurfaceTexture::drainQueueAndFreeBuffersLocked() {
- status_t err = drainQueueLocked();
- if (err == NO_ERROR) {
- if (mSynchronousMode) {
- freeAllBuffersLocked();
- } else {
- freeAllBuffersExceptHeadLocked();
- }
- }
- return err;
-}
-
EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy,
const sp<GraphicBuffer>& graphicBuffer) {
EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
diff --git a/libs/rs/RenderScriptDefines.h b/libs/rs/RenderScriptDefines.h
index d092520..5b0a3da 100644
--- a/libs/rs/RenderScriptDefines.h
+++ b/libs/rs/RenderScriptDefines.h
@@ -99,8 +99,11 @@
RS_ALLOCATION_USAGE_GRAPHICS_VERTEX = 0x0004,
RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS = 0x0008,
RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET = 0x0010,
+ RS_ALLOCATION_USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE = 0x0020,
+ RS_ALLOCATION_USAGE_IO_INPUT = 0x0040,
+ RS_ALLOCATION_USAGE_IO_OUTPUT = 0x0080,
- RS_ALLOCATION_USAGE_ALL = 0x000F
+ RS_ALLOCATION_USAGE_ALL = 0x00FF
};
enum RsAllocationMipmapControl {
diff --git a/libs/rs/driver/rsdAllocation.cpp b/libs/rs/driver/rsdAllocation.cpp
index 1f70e66..fac40f2 100644
--- a/libs/rs/driver/rsdAllocation.cpp
+++ b/libs/rs/driver/rsdAllocation.cpp
@@ -134,6 +134,13 @@
static void UploadToTexture(const Context *rsc, const Allocation *alloc) {
DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
+ if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE) {
+ if (!drv->textureID) {
+ RSD_CALL_GL(glGenTextures, 1, &drv->textureID);
+ }
+ return;
+ }
+
if (!drv->glType || !drv->glFormat) {
return;
}
@@ -370,6 +377,12 @@
drv->uploadDeferred = true;
}
+int32_t rsdAllocationInitSurfaceTexture(const Context *rsc, const Allocation *alloc) {
+ DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
+ UploadToTexture(rsc, alloc);
+ return drv->textureID;
+}
+
void rsdAllocationData1D(const Context *rsc, const Allocation *alloc,
uint32_t xoff, uint32_t lod, uint32_t count,
const void *data, uint32_t sizeBytes) {
diff --git a/libs/rs/driver/rsdAllocation.h b/libs/rs/driver/rsdAllocation.h
index 4fc4419..230804b 100644
--- a/libs/rs/driver/rsdAllocation.h
+++ b/libs/rs/driver/rsdAllocation.h
@@ -67,6 +67,8 @@
RsAllocationUsageType src);
void rsdAllocationMarkDirty(const android::renderscript::Context *rsc,
const android::renderscript::Allocation *alloc);
+int32_t rsdAllocationInitSurfaceTexture(const android::renderscript::Context *rsc,
+ const android::renderscript::Allocation *alloc);
void rsdAllocationData1D(const android::renderscript::Context *rsc,
const android::renderscript::Allocation *alloc,
diff --git a/libs/rs/driver/rsdCore.cpp b/libs/rs/driver/rsdCore.cpp
index 1a535d0..9987027 100644
--- a/libs/rs/driver/rsdCore.cpp
+++ b/libs/rs/driver/rsdCore.cpp
@@ -72,6 +72,7 @@
rsdAllocationResize,
rsdAllocationSyncAll,
rsdAllocationMarkDirty,
+ rsdAllocationInitSurfaceTexture,
rsdAllocationData1D,
rsdAllocationData2D,
rsdAllocationData3D,
diff --git a/libs/rs/driver/rsdShader.cpp b/libs/rs/driver/rsdShader.cpp
index c70193ae..056a33a 100644
--- a/libs/rs/driver/rsdShader.cpp
+++ b/libs/rs/driver/rsdShader.cpp
@@ -143,7 +143,12 @@
char buf[256];
for (uint32_t ct=0; ct < mRSProgram->mHal.state.texturesCount; ct++) {
if (mRSProgram->mHal.state.textureTargets[ct] == RS_TEXTURE_2D) {
- snprintf(buf, sizeof(buf), "uniform sampler2D UNI_Tex%i;\n", ct);
+ Allocation *a = mRSProgram->mHal.state.textures[ct];
+ if (a && a->mHal.state.surfaceTextureID) {
+ snprintf(buf, sizeof(buf), "uniform samplerExternalOES UNI_Tex%i;\n", ct);
+ } else {
+ snprintf(buf, sizeof(buf), "uniform sampler2D UNI_Tex%i;\n", ct);
+ }
mTextureTargets[ct] = GL_TEXTURE_2D;
} else {
snprintf(buf, sizeof(buf), "uniform samplerCube UNI_Tex%i;\n", ct);
@@ -190,12 +195,11 @@
char* buf = (char*) malloc(infoLen);
if (buf) {
RSD_CALL_GL(glGetShaderInfoLog, mShaderID, infoLen, NULL, buf);
- ALOGE("Could not compile shader \n%s\n", buf);
+ rsc->setError(RS_ERROR_FATAL_PROGRAM_LINK, buf);
free(buf);
}
RSD_CALL_GL(glDeleteShader, mShaderID);
mShaderID = 0;
- rsc->setError(RS_ERROR_BAD_SHADER, "Error returned from GL driver loading shader text,");
return false;
}
}
diff --git a/libs/rs/driver/rsdShaderCache.cpp b/libs/rs/driver/rsdShaderCache.cpp
index f6236e7..89d3c45 100644
--- a/libs/rs/driver/rsdShaderCache.cpp
+++ b/libs/rs/driver/rsdShaderCache.cpp
@@ -167,12 +167,11 @@
char* buf = (char*) malloc(bufLength);
if (buf) {
glGetProgramInfoLog(pgm, bufLength, NULL, buf);
- ALOGE("Could not link program:\n%s\n", buf);
+ rsc->setError(RS_ERROR_FATAL_PROGRAM_LINK, buf);
free(buf);
}
}
glDeleteProgram(pgm);
- rsc->setError(RS_ERROR_FATAL_PROGRAM_LINK, "Error linking GL Programs");
return false;
}
diff --git a/libs/rs/driver/rsdShaderCache.h b/libs/rs/driver/rsdShaderCache.h
index 17ee3e8..d64780b 100644
--- a/libs/rs/driver/rsdShaderCache.h
+++ b/libs/rs/driver/rsdShaderCache.h
@@ -108,6 +108,7 @@
}
if (numFragUnis) {
fragUniforms = new UniformData[numFragUnis];
+ fragUniformIsSTO = new bool[numFragUnis];
}
}
~ProgramEntry() {
@@ -123,6 +124,10 @@
delete[] fragUniforms;
fragUniforms = NULL;
}
+ if (fragUniformIsSTO) {
+ delete[] fragUniformIsSTO;
+ fragUniformIsSTO = NULL;
+ }
}
uint32_t vtx;
uint32_t frag;
@@ -131,6 +136,7 @@
AttrData *vtxAttrs;
UniformData *vtxUniforms;
UniformData *fragUniforms;
+ bool *fragUniformIsSTO;
};
android::Vector<ProgramEntry*> mEntries;
ProgramEntry *mCurrent;
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index ffb1196..09a2986 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -63,7 +63,10 @@
ret RsAllocation
}
-
+AllocationGetSurfaceTextureID {
+ param RsAllocation alloc
+ ret int32_t
+}
ContextFinish {
sync
diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp
index fd85b07..5f45abf 100644
--- a/libs/rs/rsAllocation.cpp
+++ b/libs/rs/rsAllocation.cpp
@@ -413,6 +413,12 @@
ALOGE("not implemented");
}
+int32_t Allocation::getSurfaceTextureID(const Context *rsc) {
+ int32_t id = rsc->mHal.funcs.allocation.initSurfaceTexture(rsc, this);
+ mHal.state.surfaceTextureID = id;
+ return id;
+}
+
/////////////////
//
@@ -658,6 +664,11 @@
(RsAllocationCubemapFace)srcFace);
}
+int32_t rsi_AllocationGetSurfaceTextureID(Context *rsc, RsAllocation valloc) {
+ Allocation *alloc = static_cast<Allocation *>(valloc);
+ return alloc->getSurfaceTextureID(rsc);
+}
+
}
}
diff --git a/libs/rs/rsAllocation.h b/libs/rs/rsAllocation.h
index 20201ca..a26d835 100644
--- a/libs/rs/rsAllocation.h
+++ b/libs/rs/rsAllocation.h
@@ -55,6 +55,8 @@
bool hasMipmaps;
bool hasFaces;
bool hasReferences;
+ void * usrPtr;
+ int32_t surfaceTextureID;
};
State state;
@@ -123,6 +125,7 @@
return mHal.state.mipmapControl != RS_ALLOCATION_MIPMAP_NONE;
}
+ int32_t getSurfaceTextureID(const Context *rsc);
protected:
Vector<const Program *> mToDirtyList;
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index 04284dd..1a34bd5 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -248,7 +248,7 @@
rsc->mRunning = true;
if (!rsc->mIsGraphicsContext) {
while (!rsc->mExit) {
- rsc->mIO.playCoreCommands(rsc, true, -1);
+ rsc->mIO.playCoreCommands(rsc, -1);
}
} else {
#ifndef ANDROID_RS_SERIALIZE
@@ -268,14 +268,14 @@
vsyncRate = targetRate;
}
if (targetRate) {
- drawOnce |= rsc->mIO.playCoreCommands(rsc, true, displayEvent.getFd());
+ drawOnce |= rsc->mIO.playCoreCommands(rsc, displayEvent.getFd());
while (displayEvent.getEvents(eventBuffer, 1) != 0) {
//ALOGE("vs2 time past %lld", (rsc->getTime() - eventBuffer[0].header.timestamp) / 1000000);
}
} else
#endif
{
- drawOnce |= rsc->mIO.playCoreCommands(rsc, true, -1);
+ drawOnce |= rsc->mIO.playCoreCommands(rsc, -1);
}
if ((rsc->mRootScript.get() != NULL) && rsc->mHasSurface &&
diff --git a/libs/rs/rsThreadIO.cpp b/libs/rs/rsThreadIO.cpp
index 8e4b988..4f30573 100644
--- a/libs/rs/rsThreadIO.cpp
+++ b/libs/rs/rsThreadIO.cpp
@@ -89,7 +89,7 @@
//mToCore.setTimeoutCallback(cb, dat, timeout);
}
-bool ThreadIO::playCoreCommands(Context *con, bool waitForCommand, int waitFd) {
+bool ThreadIO::playCoreCommands(Context *con, int waitFd) {
bool ret = false;
uint8_t buf[2 * 1024];
@@ -132,7 +132,6 @@
if (con->props.mLogTimes) {
con->timerSet(Context::RS_TIMER_INTERNAL);
}
- waitForCommand = false;
//ALOGV("playCoreCommands 3 %i %i", cmd->cmdID, cmd->bytes);
if (cmd->cmdID >= (sizeof(gPlaybackFuncs) / sizeof(void *))) {
diff --git a/libs/rs/rsThreadIO.h b/libs/rs/rsThreadIO.h
index d56a1c9..62e3e33 100644
--- a/libs/rs/rsThreadIO.h
+++ b/libs/rs/rsThreadIO.h
@@ -36,7 +36,7 @@
// Plays back commands from the client.
// Returns true if any commands were processed.
- bool playCoreCommands(Context *con, bool waitForCommand, int waitFd);
+ bool playCoreCommands(Context *con, int waitFd);
void setTimeoutCallback(void (*)(void *), void *, uint64_t timeout);
diff --git a/libs/rs/rs_hal.h b/libs/rs/rs_hal.h
index b8d7351..0afc94b 100644
--- a/libs/rs/rs_hal.h
+++ b/libs/rs/rs_hal.h
@@ -114,6 +114,7 @@
bool zeroNew);
void (*syncAll)(const Context *rsc, const Allocation *alloc, RsAllocationUsageType src);
void (*markDirty)(const Context *rsc, const Allocation *alloc);
+ int32_t (*initSurfaceTexture)(const Context *rsc, const Allocation *alloc);
void (*data1D)(const Context *rsc, const Allocation *alloc,
uint32_t xoff, uint32_t lod, uint32_t count,
diff --git a/libs/rs/rsg_generator.c b/libs/rs/rsg_generator.c
index 7a90597..385c8b5 100644
--- a/libs/rs/rsg_generator.c
+++ b/libs/rs/rsg_generator.c
@@ -465,7 +465,14 @@
fprintf(f, ");\n");
if (hasInlineDataPointers(api)) {
- fprintf(f, " if (cmdSizeBytes == sizeof(RS_CMD_%s)) {\n", api->name);
+ fprintf(f, " size_t totalSize = 0;\n");
+ for (ct2=0; ct2 < api->paramCount; ct2++) {
+ if (api->params[ct2].ptrLevel) {
+ fprintf(f, " totalSize += cmd->%s_length;\n", api->params[ct2].name);
+ }
+ }
+
+ fprintf(f, " if ((totalSize != 0) && (cmdSizeBytes == sizeof(RS_CMD_%s))) {\n", api->name);
fprintf(f, " con->mIO.coreSetReturn(NULL, 0);\n");
fprintf(f, " }\n");
} else if (api->ret.typeName[0]) {
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 78eb89f..9748d3b 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -48,6 +48,7 @@
private final Context mContext;
private long mVolumeKeyUpTime;
private int mVolumeControlStream = -1;
+ private final boolean mUseMasterVolume;
private static String TAG = "AudioManager";
/**
@@ -90,7 +91,8 @@
* @see #EXTRA_VIBRATE_SETTING
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String VIBRATE_SETTING_CHANGED_ACTION = "android.media.VIBRATE_SETTING_CHANGED";
+ public static final String VIBRATE_SETTING_CHANGED_ACTION =
+ "android.media.VIBRATE_SETTING_CHANGED";
/**
* @hide Broadcast intent when the volume for a particular stream type changes.
@@ -104,6 +106,27 @@
public static final String VOLUME_CHANGED_ACTION = "android.media.VOLUME_CHANGED_ACTION";
/**
+ * @hide Broadcast intent when the master volume changes.
+ * Includes the new volume
+ *
+ * @see #EXTRA_MASTER_VOLUME_VALUE
+ * @see #EXTRA_PREV_MASTER_VOLUME_VALUE
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String MASTER_VOLUME_CHANGED_ACTION =
+ "android.media.MASTER_VOLUME_CHANGED_ACTION";
+
+ /**
+ * @hide Broadcast intent when the master mute state changes.
+ * Includes the the new volume
+ *
+ * @see #EXTRA_MASTER_VOLUME_MUTED
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String MASTER_MUTE_CHANGED_ACTION =
+ "android.media.MASTER_MUTE_CHANGED_ACTION";
+
+ /**
* The new vibrate setting for a particular type.
*
* @see #VIBRATE_SETTING_CHANGED_ACTION
@@ -140,6 +163,27 @@
public static final String EXTRA_PREV_VOLUME_STREAM_VALUE =
"android.media.EXTRA_PREV_VOLUME_STREAM_VALUE";
+ /**
+ * @hide The new master volume value for the master volume changed intent.
+ * Value is integer between 0 and 100 inclusive.
+ */
+ public static final String EXTRA_MASTER_VOLUME_VALUE =
+ "android.media.EXTRA_MASTER_VOLUME_VALUE";
+
+ /**
+ * @hide The previous master volume value for the master volume changed intent.
+ * Value is integer between 0 and 100 inclusive.
+ */
+ public static final String EXTRA_PREV_MASTER_VOLUME_VALUE =
+ "android.media.EXTRA_PREV_MASTER_VOLUME_VALUE";
+
+ /**
+ * @hide The new master volume mute state for the master mute changed intent.
+ * Value is boolean
+ */
+ public static final String EXTRA_MASTER_VOLUME_MUTED =
+ "android.media.EXTRA_MASTER_VOLUME_MUTED";
+
/** The audio stream for phone calls */
public static final int STREAM_VOICE_CALL = AudioSystem.STREAM_VOICE_CALL;
/** The audio stream for system sounds */
@@ -354,6 +398,8 @@
*/
public AudioManager(Context context) {
mContext = context;
+ mUseMasterVolume = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_useMasterVolume);
}
private static IAudioService getService()
@@ -369,11 +415,12 @@
/**
* @hide
*/
- public void preDispatchKeyEvent(int keyCode, int stream) {
+ public void preDispatchKeyEvent(KeyEvent event, int stream) {
/*
* If the user hits another key within the play sound delay, then
* cancel the sound
*/
+ int keyCode = event.getKeyCode();
if (keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYCODE_VOLUME_UP
&& keyCode != KeyEvent.KEYCODE_VOLUME_MUTE
&& mVolumeKeyUpTime + VolumePanel.PLAY_SOUND_DELAY
@@ -382,15 +429,20 @@
* The user has hit another key during the delay (e.g., 300ms)
* since the last volume key up, so cancel any sounds.
*/
- adjustSuggestedStreamVolume(AudioManager.ADJUST_SAME,
+ if (mUseMasterVolume) {
+ adjustMasterVolume(ADJUST_SAME, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
+ } else {
+ adjustSuggestedStreamVolume(ADJUST_SAME,
stream, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
+ }
}
}
/**
* @hide
*/
- public void handleKeyDown(int keyCode, int stream) {
+ public void handleKeyDown(KeyEvent event, int stream) {
+ int keyCode = event.getKeyCode();
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN:
@@ -399,19 +451,33 @@
* responsive to the user.
*/
int flags = FLAG_SHOW_UI | FLAG_VIBRATE;
- if (mVolumeControlStream != -1) {
- stream = mVolumeControlStream;
- flags |= FLAG_FORCE_STREAM;
+ if (mUseMasterVolume) {
+ adjustMasterVolume(
+ keyCode == KeyEvent.KEYCODE_VOLUME_UP
+ ? ADJUST_RAISE
+ : ADJUST_LOWER,
+ flags);
+ } else {
+ if (mVolumeControlStream != -1) {
+ stream = mVolumeControlStream;
+ flags |= FLAG_FORCE_STREAM;
+ }
+ adjustSuggestedStreamVolume(
+ keyCode == KeyEvent.KEYCODE_VOLUME_UP
+ ? ADJUST_RAISE
+ : ADJUST_LOWER,
+ stream,
+ flags);
}
- adjustSuggestedStreamVolume(
- keyCode == KeyEvent.KEYCODE_VOLUME_UP
- ? ADJUST_RAISE
- : ADJUST_LOWER,
- stream,
- flags);
break;
case KeyEvent.KEYCODE_VOLUME_MUTE:
- // TODO: Actually handle MUTE.
+ if (event.getRepeatCount() == 0) {
+ if (mUseMasterVolume) {
+ setMasterMute(!isMasterMute());
+ } else {
+ // TODO: Actually handle MUTE.
+ }
+ }
break;
}
}
@@ -419,7 +485,8 @@
/**
* @hide
*/
- public void handleKeyUp(int keyCode, int stream) {
+ public void handleKeyUp(KeyEvent event, int stream) {
+ int keyCode = event.getKeyCode();
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN:
@@ -427,21 +494,24 @@
* Play a sound. This is done on key up since we don't want the
* sound to play when a user holds down volume down to mute.
*/
- int flags = FLAG_PLAY_SOUND;
- if (mVolumeControlStream != -1) {
- stream = mVolumeControlStream;
- flags |= FLAG_FORCE_STREAM;
+ if (mUseMasterVolume) {
+ if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
+ adjustMasterVolume(ADJUST_SAME, FLAG_PLAY_SOUND);
+ }
+ } else {
+ int flags = FLAG_PLAY_SOUND;
+ if (mVolumeControlStream != -1) {
+ stream = mVolumeControlStream;
+ flags |= FLAG_FORCE_STREAM;
+ }
+ adjustSuggestedStreamVolume(
+ ADJUST_SAME,
+ stream,
+ flags);
}
- adjustSuggestedStreamVolume(
- ADJUST_SAME,
- stream,
- flags);
mVolumeKeyUpTime = SystemClock.uptimeMillis();
break;
- case KeyEvent.KEYCODE_VOLUME_MUTE:
- // TODO: Actually handle MUTE.
- break;
}
}
@@ -464,7 +534,11 @@
public void adjustStreamVolume(int streamType, int direction, int flags) {
IAudioService service = getService();
try {
- service.adjustStreamVolume(streamType, direction, flags);
+ if (mUseMasterVolume) {
+ service.adjustMasterVolume(direction, flags);
+ } else {
+ service.adjustStreamVolume(streamType, direction, flags);
+ }
} catch (RemoteException e) {
Log.e(TAG, "Dead object in adjustStreamVolume", e);
}
@@ -490,7 +564,11 @@
public void adjustVolume(int direction, int flags) {
IAudioService service = getService();
try {
- service.adjustVolume(direction, flags);
+ if (mUseMasterVolume) {
+ service.adjustMasterVolume(direction, flags);
+ } else {
+ service.adjustVolume(direction, flags);
+ }
} catch (RemoteException e) {
Log.e(TAG, "Dead object in adjustVolume", e);
}
@@ -516,9 +594,32 @@
public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) {
IAudioService service = getService();
try {
- service.adjustSuggestedStreamVolume(direction, suggestedStreamType, flags);
+ if (mUseMasterVolume) {
+ service.adjustMasterVolume(direction, flags);
+ } else {
+ service.adjustSuggestedStreamVolume(direction, suggestedStreamType, flags);
+ }
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in adjustVolume", e);
+ Log.e(TAG, "Dead object in adjustSuggestedStreamVolume", e);
+ }
+ }
+
+ /**
+ * Adjusts the master volume for the device's audio amplifier.
+ * <p>
+ *
+ * @param direction The direction to adjust the volume. One of
+ * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
+ * {@link #ADJUST_SAME}.
+ * @param flags One or more flags.
+ * @hide
+ */
+ public void adjustMasterVolume(int direction, int flags) {
+ IAudioService service = getService();
+ try {
+ service.adjustMasterVolume(direction, flags);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in adjustMasterVolume", e);
}
}
@@ -564,7 +665,11 @@
public int getStreamMaxVolume(int streamType) {
IAudioService service = getService();
try {
- return service.getStreamMaxVolume(streamType);
+ if (mUseMasterVolume) {
+ return service.getMasterMaxVolume();
+ } else {
+ return service.getStreamMaxVolume(streamType);
+ }
} catch (RemoteException e) {
Log.e(TAG, "Dead object in getStreamMaxVolume", e);
return 0;
@@ -582,7 +687,11 @@
public int getStreamVolume(int streamType) {
IAudioService service = getService();
try {
- return service.getStreamVolume(streamType);
+ if (mUseMasterVolume) {
+ return service.getMasterVolume();
+ } else {
+ return service.getStreamVolume(streamType);
+ }
} catch (RemoteException e) {
Log.e(TAG, "Dead object in getStreamVolume", e);
return 0;
@@ -597,7 +706,11 @@
public int getLastAudibleStreamVolume(int streamType) {
IAudioService service = getService();
try {
- return service.getLastAudibleStreamVolume(streamType);
+ if (mUseMasterVolume) {
+ return service.getLastAudibleMasterVolume();
+ } else {
+ return service.getLastAudibleStreamVolume(streamType);
+ }
} catch (RemoteException e) {
Log.e(TAG, "Dead object in getLastAudibleStreamVolume", e);
return 0;
@@ -640,13 +753,82 @@
public void setStreamVolume(int streamType, int index, int flags) {
IAudioService service = getService();
try {
- service.setStreamVolume(streamType, index, flags);
+ if (mUseMasterVolume) {
+ service.setMasterVolume(index, flags);
+ } else {
+ service.setStreamVolume(streamType, index, flags);
+ }
} catch (RemoteException e) {
Log.e(TAG, "Dead object in setStreamVolume", e);
}
}
/**
+ * Returns the maximum volume index for master volume.
+ *
+ * @hide
+ */
+ public int getMasterMaxVolume() {
+ IAudioService service = getService();
+ try {
+ return service.getMasterMaxVolume();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in getMasterMaxVolume", e);
+ return 0;
+ }
+ }
+
+ /**
+ * Returns the current volume index for master volume.
+ *
+ * @return The current volume index for master volume.
+ * @hide
+ */
+ public int getMasterVolume() {
+ IAudioService service = getService();
+ try {
+ return service.getMasterVolume();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in getMasterVolume", e);
+ return 0;
+ }
+ }
+
+ /**
+ * Get last audible volume before master volume was muted.
+ *
+ * @hide
+ */
+ public int getLastAudibleMasterVolume() {
+ IAudioService service = getService();
+ try {
+ return service.getLastAudibleMasterVolume();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in getLastAudibleMasterVolume", e);
+ return 0;
+ }
+ }
+
+ /**
+ * Sets the volume index for master volume.
+ *
+ * @param index The volume index to set. See
+ * {@link #getMasterMaxVolume(int)} for the largest valid value.
+ * @param flags One or more flags.
+ * @see #getMasterMaxVolume(int)
+ * @see #getMasterVolume(int)
+ * @hide
+ */
+ public void setMasterVolume(int index, int flags) {
+ IAudioService service = getService();
+ try {
+ service.setMasterVolume(index, flags);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in setMasterVolume", e);
+ }
+ }
+
+ /**
* Solo or unsolo a particular stream. All other streams are muted.
* <p>
* The solo command is protected against client process death: if a process
@@ -717,6 +899,35 @@
}
/**
+ * set master mute state.
+ *
+ * @hide
+ */
+ public void setMasterMute(boolean state) {
+ IAudioService service = getService();
+ try {
+ service.setMasterMute(state, mICallBack);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in setMasterMute", e);
+ }
+ }
+
+ /**
+ * get master mute state.
+ *
+ * @hide
+ */
+ public boolean isMasterMute() {
+ IAudioService service = getService();
+ try {
+ return service.isMasterMute();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in isMasterMute", e);
+ return false;
+ }
+ }
+
+ /**
* forces the stream controlled by hard volume keys
* specifying streamType == -1 releases control to the
* logic.
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 13e3982..eae03be 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -112,6 +112,7 @@
// AudioHandler message.whats
private static final int MSG_SET_DEVICE_VOLUME = 0;
private static final int MSG_PERSIST_VOLUME = 1;
+ private static final int MSG_PERSIST_MASTER_VOLUME = 2;
private static final int MSG_PERSIST_RINGER_MODE = 3;
private static final int MSG_PERSIST_VIBRATE_SETTING = 4;
private static final int MSG_MEDIA_SERVER_DIED = 5;
@@ -136,7 +137,6 @@
// Timeout for connection to bluetooth headset service
private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
-
/** @see AudioSystemThread */
private AudioSystemThread mAudioSystemThread;
/** @see AudioHandler */
@@ -155,6 +155,10 @@
private static final int NUM_SOUNDPOOL_CHANNELS = 4;
private static final int SOUND_EFFECT_VOLUME = 1000;
+ // Internally master volume is a float in the 0.0 - 1.0 range,
+ // but to support integer based AudioManager API we translate it to 0 - 100
+ private static final int MAX_MASTER_VOLUME = 100;
+
/* Sound effect file names */
private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
private static final String[] SOUND_EFFECT_FILES = new String[] {
@@ -275,6 +279,11 @@
// Forced device usage for communications
private int mForcedUseForComm;
+ // True if we have master volume support
+ private final boolean mUseMasterVolume;
+
+ private final int[] mMasterVolumeRamp;
+
// List of binder death handlers for setMode() client processes.
// The last process to have called setMode() is at the top of the list.
private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
@@ -401,6 +410,13 @@
TelephonyManager tmgr = (TelephonyManager)
context.getSystemService(Context.TELEPHONY_SERVICE);
tmgr.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
+
+ mUseMasterVolume = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_useMasterVolume);
+ restoreMasterVolume();
+
+ mMasterVolumeRamp = context.getResources().getIntArray(
+ com.android.internal.R.array.config_masterVolumeRamp);
}
private void createAudioSystemThread() {
@@ -602,6 +618,32 @@
sendVolumeUpdate(streamType, oldIndex, index, flags);
}
+ /** @see AudioManager#adjustMasterVolume(int) */
+ public void adjustMasterVolume(int direction, int flags) {
+ ensureValidDirection(direction);
+ int volume = Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
+ int delta = 0;
+ for (int i = 0; i < mMasterVolumeRamp.length; i += 2) {
+ int testVolume = mMasterVolumeRamp[i];
+ int testDelta = mMasterVolumeRamp[i + 1];
+ if (direction == AudioManager.ADJUST_RAISE) {
+ if (volume >= testVolume) {
+ delta = testDelta;
+ } else {
+ break;
+ }
+ } else if (direction == AudioManager.ADJUST_LOWER) {
+ if (volume - testDelta >= testVolume) {
+ delta = -testDelta;
+ } else {
+ break;
+ }
+ }
+ }
+// Log.d(TAG, "adjustMasterVolume volume: " + volume + " delta: " + delta + " direction: " + direction);
+ setMasterVolume(volume + delta, flags);
+ }
+
/** @see AudioManager#setStreamVolume(int, int, int) */
public void setStreamVolume(int streamType, int index, int flags) {
ensureValidStreamType(streamType);
@@ -657,6 +699,27 @@
mContext.sendBroadcast(intent);
}
+ // UI update and Broadcast Intent
+ private void sendMasterVolumeUpdate(int flags, int oldVolume, int newVolume) {
+ mVolumePanel.postMasterVolumeChanged(flags);
+
+ Intent intent = new Intent(AudioManager.MASTER_VOLUME_CHANGED_ACTION);
+ intent.putExtra(AudioManager.EXTRA_PREV_MASTER_VOLUME_VALUE, oldVolume);
+ intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_VALUE, newVolume);
+ mContext.sendBroadcast(intent);
+ }
+
+ // UI update and Broadcast Intent
+ private void sendMasterMuteUpdate(boolean muted, int flags) {
+ mVolumePanel.postMasterMuteChanged(flags);
+
+ Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
+ intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
+ long origCallerIdentityToken = Binder.clearCallingIdentity();
+ mContext.sendStickyBroadcast(intent);
+ Binder.restoreCallingIdentity(origCallerIdentityToken);
+ }
+
/**
* Sets the stream state's index, and posts a message to set system volume.
* This will not call out to the UI. Assumes a valid stream type.
@@ -725,6 +788,19 @@
return (mStreamStates[streamType].muteCount() != 0);
}
+ /** @see AudioManager#setMasterMute(boolean, IBinder) */
+ public void setMasterMute(boolean state, IBinder cb) {
+ if (state != AudioSystem.getMasterMute()) {
+ AudioSystem.setMasterMute(state);
+ sendMasterMuteUpdate(state, AudioManager.FLAG_SHOW_UI);
+ }
+ }
+
+ /** get master mute state. */
+ public boolean isMasterMute() {
+ return AudioSystem.getMasterMute();
+ }
+
/** @see AudioManager#getStreamVolume(int) */
public int getStreamVolume(int streamType) {
ensureValidStreamType(streamType);
@@ -732,12 +808,45 @@
return (mStreamStates[streamType].getIndex(device, false /* lastAudible */) + 5) / 10;
}
+ public int getMasterVolume() {
+ if (isMasterMute()) return 0;
+ return getLastAudibleMasterVolume();
+ }
+
+ public void setMasterVolume(int volume, int flags) {
+ if (volume < 0) {
+ volume = 0;
+ } else if (volume > MAX_MASTER_VOLUME) {
+ volume = MAX_MASTER_VOLUME;
+ }
+ doSetMasterVolume((float)volume / MAX_MASTER_VOLUME, flags);
+ }
+
+ private void doSetMasterVolume(float volume, int flags) {
+ // don't allow changing master volume when muted
+ if (!AudioSystem.getMasterMute()) {
+ int oldVolume = getMasterVolume();
+ AudioSystem.setMasterVolume(volume);
+
+ int newVolume = getMasterVolume();
+ if (newVolume != oldVolume) {
+ // Post a persist master volume msg
+ sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME, SENDMSG_REPLACE,
+ Math.round(volume * (float)1000.0), 0, null, PERSIST_DELAY);
+ sendMasterVolumeUpdate(flags, oldVolume, newVolume);
+ }
+ }
+ }
+
/** @see AudioManager#getStreamMaxVolume(int) */
public int getStreamMaxVolume(int streamType) {
ensureValidStreamType(streamType);
return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
}
+ public int getMasterMaxVolume() {
+ return MAX_MASTER_VOLUME;
+ }
/** Get last audible volume before stream was muted. */
public int getLastAudibleStreamVolume(int streamType) {
@@ -746,6 +855,11 @@
return (mStreamStates[streamType].getIndex(device, true /* lastAudible */) + 5) / 10;
}
+ /** Get last audible master volume before it was muted. */
+ public int getLastAudibleMasterVolume() {
+ return Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
+ }
+
/** @see AudioManager#getRingerMode() */
public int getRingerMode() {
synchronized(mSettingsLock) {
@@ -816,6 +930,16 @@
}
}
+ private void restoreMasterVolume() {
+ if (mUseMasterVolume) {
+ float volume = Settings.System.getFloat(mContentResolver,
+ Settings.System.VOLUME_MASTER, -1.0f);
+ if (volume >= 0.0f) {
+ AudioSystem.setMasterVolume(volume);
+ }
+ }
+ }
+
/** @see AudioManager#shouldVibrate(int) */
public boolean shouldVibrate(int vibrateType) {
@@ -2355,6 +2479,11 @@
persistVolume((VolumeStreamState) msg.obj, msg.arg1, msg.arg2);
break;
+ case MSG_PERSIST_MASTER_VOLUME:
+ Settings.System.putFloat(mContentResolver, Settings.System.VOLUME_MASTER,
+ (float)msg.arg1 / (float)1000.0);
+ break;
+
case MSG_PERSIST_RINGER_MODE:
// note that the value persisted is the current ringer mode, not the
// value of ringer mode as of the time the request was made to persist
@@ -2415,6 +2544,9 @@
// Restore ringer mode
setRingerModeInt(getRingerMode(), false);
+ // Restore master volume
+ restoreMasterVolume();
+
// indicate the end of reconfiguration phase to audio HAL
AudioSystem.setParameters("restarting=false");
break;
@@ -2839,6 +2971,11 @@
adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
BluetoothProfile.A2DP);
}
+
+ if (mUseMasterVolume) {
+ // Send sticky broadcast for initial master mute state
+ sendMasterMuteUpdate(false, 0);
+ }
} else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)) {
if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
// a package is being removed, not replaced
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 3080497..d354cdb 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -318,5 +318,9 @@
public static native int initStreamVolume(int stream, int indexMin, int indexMax);
public static native int setStreamVolumeIndex(int stream, int index, int device);
public static native int getStreamVolumeIndex(int stream, int device);
+ public static native int setMasterVolume(float value);
+ public static native float getMasterVolume();
+ public static native int setMasterMute(boolean mute);
+ public static native boolean getMasterMute();
public static native int getDevicesForStream(int stream);
}
diff --git a/media/java/android/media/CamcorderProfile.java b/media/java/android/media/CamcorderProfile.java
index 7d60c55..e94bddc 100644
--- a/media/java/android/media/CamcorderProfile.java
+++ b/media/java/android/media/CamcorderProfile.java
@@ -20,12 +20,12 @@
import android.hardware.Camera.CameraInfo;
/**
- * The CamcorderProfile class is used to retrieve the
+ * Retrieves the
* predefined camcorder profile settings for camcorder applications.
* These settings are read-only.
*
- * The compressed output from a recording session with a given
- * CamcorderProfile contains two tracks: one for auido and one for video.
+ * <p>The compressed output from a recording session with a given
+ * CamcorderProfile contains two tracks: one for audio and one for video.
*
* <p>Each profile specifies the following set of parameters:
* <ul>
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 5294d36..17d8e4d 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -30,10 +30,14 @@
void adjustVolume(int direction, int flags);
void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags);
-
+
void adjustStreamVolume(int streamType, int direction, int flags);
-
+
+ void adjustMasterVolume(int direction, int flags);
+
void setStreamVolume(int streamType, int index, int flags);
+
+ void setMasterVolume(int index, int flags);
void setStreamSolo(int streamType, boolean state, IBinder cb);
@@ -41,12 +45,22 @@
boolean isStreamMute(int streamType);
+ void setMasterMute(boolean state, IBinder cb);
+
+ boolean isMasterMute();
+
int getStreamVolume(int streamType);
-
+
+ int getMasterVolume();
+
int getStreamMaxVolume(int streamType);
+
+ int getMasterMaxVolume();
int getLastAudibleStreamVolume(int streamType);
+ int getLastAudibleMasterVolume();
+
void setRingerMode(int ringerMode);
int getRingerMode();
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 9dc9cef..69ca58bf 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -1150,9 +1150,44 @@
}
}
+ static class MediaBulkDeleter {
+ StringBuilder idList = new StringBuilder();
+ IContentProvider mProvider;
+ Uri mBaseUri;
+
+ public MediaBulkDeleter(IContentProvider provider, Uri baseUri) {
+ mProvider = provider;
+ mBaseUri = baseUri;
+ }
+
+ public void delete(long id) throws RemoteException {
+ if (idList.length() != 0) {
+ idList.append(",");
+ }
+ idList.append(id);
+ if (idList.length() > 1024) {
+ flush();
+ }
+ }
+ public void flush() throws RemoteException {
+ int numrows = mProvider.delete(mBaseUri, MediaStore.MediaColumns._ID + " IN (" +
+ idList.toString() + ")", null);
+ //Log.i("@@@@@@@@@", "rows deleted: " + numrows);
+ idList.setLength(0);
+ }
+ }
+
private void postscan(String[] directories) throws RemoteException {
Iterator<FileCacheEntry> iterator = mFileCache.values().iterator();
+ // Tell the provider to not delete the file.
+ // If the file is truly gone the delete is unnecessary, and we want to avoid
+ // accidentally deleting files that are really there (this may happen if the
+ // filesystem is mounted and unmounted while the scanner is running).
+ Uri.Builder builder = mFilesUri.buildUpon();
+ builder.appendQueryParameter(MediaStore.PARAM_DELETE_DATA, "false");
+ MediaBulkDeleter deleter = new MediaBulkDeleter(mMediaProvider, builder.build());
+
while (iterator.hasNext()) {
FileCacheEntry entry = iterator.next();
String path = entry.mPath;
@@ -1176,15 +1211,6 @@
}
if (fileMissing) {
- // Tell the provider to not delete the file.
- // If the file is truly gone the delete is unnecessary, and we want to avoid
- // accidentally deleting files that are really there (this may happen if the
- // filesystem is mounted and unmounted while the scanner is running).
- Uri.Builder builder = mFilesUri.buildUpon();
- builder.appendEncodedPath(String.valueOf(entry.mRowId));
- builder.appendQueryParameter(MediaStore.PARAM_DELETE_DATA, "false");
- Uri missingUri = builder.build();
-
// do not delete missing playlists, since they may have been modified by the user.
// the user can delete them in the media player instead.
// instead, clear the path and lastModified fields in the row
@@ -1192,15 +1218,17 @@
int fileType = (mediaFileType == null ? 0 : mediaFileType.fileType);
if (!MediaFile.isPlayListFileType(fileType)) {
- mMediaProvider.delete(missingUri, null, null);
+ deleter.delete(entry.mRowId);
iterator.remove();
if (entry.mPath.toLowerCase(Locale.US).endsWith("/.nomedia")) {
+ deleter.flush();
File f = new File(path);
mMediaProvider.call(MediaStore.UNHIDE_CALL, f.getParent(), null);
}
}
}
}
+ deleter.flush();
// handle playlists last, after we know what media files are on the storage.
if (mProcessPlaylists) {
diff --git a/media/jni/mediaeditor/Android.mk b/media/jni/mediaeditor/Android.mk
index e44dc7c..b17ae45 100755
--- a/media/jni/mediaeditor/Android.mk
+++ b/media/jni/mediaeditor/Android.mk
@@ -57,6 +57,7 @@
libaudioflinger \
libbinder \
libstagefright \
+ libstagefright_foundation \
libstagefright_omx \
libgui \
libvideoeditorplayer
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index 0d51def..df4fbb5 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -840,7 +840,7 @@
void SoundChannel::setRate(float rate)
{
Mutex::Autolock lock(&mLock);
- if (mAudioTrack != 0 && mSample.get() != 0) {
+ if (mAudioTrack != NULL && mSample != 0) {
uint32_t sampleRate = uint32_t(float(mSample->sampleRate()) * rate + 0.5);
mAudioTrack->setSampleRate(sampleRate);
mRate = rate;
@@ -852,7 +852,8 @@
{
mLeftVolume = leftVolume;
mRightVolume = rightVolume;
- if (mAudioTrack != 0) mAudioTrack->setVolume(leftVolume, rightVolume);
+ if (mAudioTrack != NULL)
+ mAudioTrack->setVolume(leftVolume, rightVolume);
}
void SoundChannel::setVolume(float leftVolume, float rightVolume)
@@ -864,7 +865,7 @@
void SoundChannel::setLoop(int loop)
{
Mutex::Autolock lock(&mLock);
- if (mAudioTrack != 0 && mSample.get() != 0) {
+ if (mAudioTrack != NULL && mSample != 0) {
uint32_t loopEnd = mSample->size()/mNumChannels/
((mSample->format() == AUDIO_FORMAT_PCM_16_BIT) ? sizeof(int16_t) : sizeof(uint8_t));
mAudioTrack->setLoop(0, loopEnd, loop);
diff --git a/media/jni/soundpool/SoundPool.h b/media/jni/soundpool/SoundPool.h
index 6b11c28..002b045 100644
--- a/media/jni/soundpool/SoundPool.h
+++ b/media/jni/soundpool/SoundPool.h
@@ -116,7 +116,7 @@
class SoundChannel : public SoundEvent {
public:
enum state { IDLE, RESUMING, STOPPING, PAUSED, PLAYING };
- SoundChannel() : mAudioTrack(0), mState(IDLE), mNumChannels(1),
+ SoundChannel() : mAudioTrack(NULL), mState(IDLE), mNumChannels(1),
mPos(0), mToggle(0), mAutoPaused(false) {}
~SoundChannel();
void init(SoundPool* soundPool);
diff --git a/media/libeffects/factory/EffectsFactory.c b/media/libeffects/factory/EffectsFactory.c
index 9f6599f..59cd9e3 100644
--- a/media/libeffects/factory/EffectsFactory.c
+++ b/media/libeffects/factory/EffectsFactory.c
@@ -53,8 +53,8 @@
static lib_entry_t *getLibrary(const char *path);
static void resetEffectEnumeration();
static uint32_t updateNumEffects();
-static int findEffect(effect_uuid_t *type,
- effect_uuid_t *uuid,
+static int findEffect(const effect_uuid_t *type,
+ const effect_uuid_t *uuid,
lib_entry_t **lib,
effect_descriptor_t **desc);
static void dumpEffectDescriptor(effect_descriptor_t *desc, char *str, size_t len);
@@ -236,7 +236,7 @@
return ret;
}
-int EffectGetDescriptor(effect_uuid_t *uuid, effect_descriptor_t *pDescriptor)
+int EffectGetDescriptor(const effect_uuid_t *uuid, effect_descriptor_t *pDescriptor)
{
lib_entry_t *l = NULL;
effect_descriptor_t *d = NULL;
@@ -257,7 +257,7 @@
return ret;
}
-int EffectCreate(effect_uuid_t *uuid, int32_t sessionId, int32_t ioId, effect_handle_t *pHandle)
+int EffectCreate(const effect_uuid_t *uuid, int32_t sessionId, int32_t ioId, effect_handle_t *pHandle)
{
list_elem_t *e = gLibraryList;
lib_entry_t *l = NULL;
@@ -372,7 +372,7 @@
return ret;
}
-int EffectIsNullUuid(effect_uuid_t *uuid)
+int EffectIsNullUuid(const effect_uuid_t *uuid)
{
if (memcmp(uuid, EFFECT_UUID_NULL, sizeof(effect_uuid_t))) {
return 0;
@@ -628,8 +628,8 @@
return cnt;
}
-int findEffect(effect_uuid_t *type,
- effect_uuid_t *uuid,
+int findEffect(const effect_uuid_t *type,
+ const effect_uuid_t *uuid,
lib_entry_t **lib,
effect_descriptor_t **desc)
{
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index 108d36a..3714283 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -195,7 +195,7 @@
return 0;
} /* end EffectQueryEffect */
-extern "C" int EffectCreate(effect_uuid_t *uuid,
+extern "C" int EffectCreate(const effect_uuid_t *uuid,
int32_t sessionId,
int32_t ioId,
effect_handle_t *pHandle){
@@ -471,7 +471,7 @@
} /* end EffectRelease */
-extern "C" int EffectGetDescriptor(effect_uuid_t *uuid,
+extern "C" int EffectGetDescriptor(const effect_uuid_t *uuid,
effect_descriptor_t *pDescriptor) {
const effect_descriptor_t *desc = NULL;
diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
index 09cd5cc..358357e 100755
--- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
@@ -210,7 +210,7 @@
return 0;
} /* end EffectQueryEffect */
-extern "C" int EffectCreate(effect_uuid_t *uuid,
+extern "C" int EffectCreate(const effect_uuid_t *uuid,
int32_t sessionId,
int32_t ioId,
effect_handle_t *pHandle){
@@ -317,7 +317,7 @@
return 0;
} /* end EffectRelease */
-extern "C" int EffectGetDescriptor(effect_uuid_t *uuid,
+extern "C" int EffectGetDescriptor(const effect_uuid_t *uuid,
effect_descriptor_t *pDescriptor) {
int i;
int length = sizeof(gDescriptors) / sizeof(const effect_descriptor_t *);
diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp
index 9fd6764..4d94a75 100755
--- a/media/libeffects/preprocessing/PreProcessing.cpp
+++ b/media/libeffects/preprocessing/PreProcessing.cpp
@@ -1072,7 +1072,7 @@
return sInitStatus;
}
-const effect_descriptor_t *PreProc_GetDescriptor(effect_uuid_t *uuid)
+const effect_descriptor_t *PreProc_GetDescriptor(const effect_uuid_t *uuid)
{
size_t i;
for (i = 0; i < PREPROC_NUM_EFFECTS; i++) {
@@ -1568,7 +1568,7 @@
return 0;
}
-int PreProcessingLib_Create(effect_uuid_t *uuid,
+int PreProcessingLib_Create(const effect_uuid_t *uuid,
int32_t sessionId,
int32_t ioId,
effect_handle_t *pInterface)
@@ -1620,7 +1620,7 @@
return Session_ReleaseEffect(fx->session, fx);
}
-int PreProcessingLib_GetDescriptor(effect_uuid_t *uuid,
+int PreProcessingLib_GetDescriptor(const effect_uuid_t *uuid,
effect_descriptor_t *pDescriptor) {
if (pDescriptor == NULL || uuid == NULL){
diff --git a/media/libeffects/testlibs/EffectEqualizer.cpp b/media/libeffects/testlibs/EffectEqualizer.cpp
index 5241660..35a4a61 100644
--- a/media/libeffects/testlibs/EffectEqualizer.cpp
+++ b/media/libeffects/testlibs/EffectEqualizer.cpp
@@ -140,7 +140,7 @@
return 0;
} /* end EffectQueryNext */
-extern "C" int EffectCreate(effect_uuid_t *uuid,
+extern "C" int EffectCreate(const effect_uuid_t *uuid,
int32_t sessionId,
int32_t ioId,
effect_handle_t *pHandle) {
@@ -195,7 +195,7 @@
return 0;
} /* end EffectRelease */
-extern "C" int EffectGetDescriptor(effect_uuid_t *uuid,
+extern "C" int EffectGetDescriptor(const effect_uuid_t *uuid,
effect_descriptor_t *pDescriptor) {
if (pDescriptor == NULL || uuid == NULL){
diff --git a/media/libeffects/testlibs/EffectReverb.c b/media/libeffects/testlibs/EffectReverb.c
index ebb72c1..83517120 100644
--- a/media/libeffects/testlibs/EffectReverb.c
+++ b/media/libeffects/testlibs/EffectReverb.c
@@ -111,7 +111,7 @@
return 0;
}
-int EffectCreate(effect_uuid_t *uuid,
+int EffectCreate(const effect_uuid_t *uuid,
int32_t sessionId,
int32_t ioId,
effect_handle_t *pHandle) {
@@ -182,7 +182,7 @@
return 0;
}
-int EffectGetDescriptor(effect_uuid_t *uuid,
+int EffectGetDescriptor(const effect_uuid_t *uuid,
effect_descriptor_t *pDescriptor) {
int i;
int length = sizeof(gDescriptors) / sizeof(const effect_descriptor_t *);
diff --git a/media/libeffects/testlibs/EffectReverb.h b/media/libeffects/testlibs/EffectReverb.h
index 5137074..1fb14a7 100644
--- a/media/libeffects/testlibs/EffectReverb.h
+++ b/media/libeffects/testlibs/EffectReverb.h
@@ -303,12 +303,12 @@
int EffectQueryNumberEffects(uint32_t *pNumEffects);
int EffectQueryEffect(uint32_t index,
effect_descriptor_t *pDescriptor);
-int EffectCreate(effect_uuid_t *effectUID,
+int EffectCreate(const effect_uuid_t *effectUID,
int32_t sessionId,
int32_t ioId,
effect_handle_t *pHandle);
int EffectRelease(effect_handle_t handle);
-int EffectGetDescriptor(effect_uuid_t *uuid,
+int EffectGetDescriptor(const effect_uuid_t *uuid,
effect_descriptor_t *pDescriptor);
static int Reverb_Process(effect_handle_t self,
diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp
index 5d70a9b..51c8b68 100644
--- a/media/libeffects/visualizer/EffectVisualizer.cpp
+++ b/media/libeffects/visualizer/EffectVisualizer.cpp
@@ -190,7 +190,7 @@
return 0;
}
-int VisualizerLib_Create(effect_uuid_t *uuid,
+int VisualizerLib_Create(const effect_uuid_t *uuid,
int32_t sessionId,
int32_t ioId,
effect_handle_t *pHandle) {
@@ -240,7 +240,7 @@
return 0;
}
-int VisualizerLib_GetDescriptor(effect_uuid_t *uuid,
+int VisualizerLib_GetDescriptor(const effect_uuid_t *uuid,
effect_descriptor_t *pDescriptor) {
if (pDescriptor == NULL || uuid == NULL){
diff --git a/media/libmedia/AudioEffect.cpp b/media/libmedia/AudioEffect.cpp
index a242846..f9f997f 100644
--- a/media/libmedia/AudioEffect.cpp
+++ b/media/libmedia/AudioEffect.cpp
@@ -159,7 +159,7 @@
mCblk->buffer = (uint8_t *)mCblk + bufOffset;
iEffect->asBinder()->linkToDeath(mIEffectClient);
- ALOGV("set() %p OK effect: %s id: %d status %d enabled %d, ", this, mDescriptor.name, mId, mStatus, mEnabled);
+ ALOGV("set() %p OK effect: %s id: %d status %d enabled %d", this, mDescriptor.name, mId, mStatus, mEnabled);
return mStatus;
}
@@ -412,7 +412,8 @@
return af->queryEffect(index, descriptor);
}
-status_t AudioEffect::getEffectDescriptor(effect_uuid_t *uuid, effect_descriptor_t *descriptor)
+status_t AudioEffect::getEffectDescriptor(const effect_uuid_t *uuid,
+ effect_descriptor_t *descriptor) /*const*/
{
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index c96bc76..b74b3e3 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -293,7 +293,6 @@
return WOULD_BLOCK;
}
}
- t->mLock.lock();
}
AutoMutex lock(mLock);
@@ -334,10 +333,6 @@
}
}
- if (t != 0) {
- t->mLock.unlock();
- }
-
return ret;
}
@@ -347,10 +342,6 @@
ALOGV("stop");
- if (t != 0) {
- t->mLock.lock();
- }
-
AutoMutex lock(mLock);
if (mActive == 1) {
mActive = 0;
@@ -367,10 +358,6 @@
}
}
- if (t != 0) {
- t->mLock.unlock();
- }
-
return NO_ERROR;
}
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 110a294..ec4c044 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -121,7 +121,8 @@
return NO_ERROR;
}
-status_t AudioSystem::setStreamVolume(audio_stream_type_t stream, float value, int output)
+status_t AudioSystem::setStreamVolume(audio_stream_type_t stream, float value,
+ audio_io_handle_t output)
{
if (uint32_t(stream) >= AUDIO_STREAM_CNT) return BAD_VALUE;
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
@@ -139,7 +140,8 @@
return NO_ERROR;
}
-status_t AudioSystem::getStreamVolume(audio_stream_type_t stream, float* volume, int output)
+status_t AudioSystem::getStreamVolume(audio_stream_type_t stream, float* volume,
+ audio_io_handle_t output)
{
if (uint32_t(stream) >= AUDIO_STREAM_CNT) return BAD_VALUE;
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
@@ -402,7 +404,8 @@
ALOGW("AudioFlinger server died!");
}
-void AudioSystem::AudioFlingerClient::ioConfigChanged(int event, int ioHandle, void *param2) {
+void AudioSystem::AudioFlingerClient::ioConfigChanged(int event, audio_io_handle_t ioHandle,
+ void *param2) {
ALOGV("ioConfigChanged() event %d", event);
OutputDescriptor *desc;
audio_stream_type_t stream;
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 8c33f41..087d7b2 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -345,7 +345,6 @@
return;
}
}
- t->mLock.lock();
}
AutoMutex lock(mLock);
@@ -396,9 +395,6 @@
}
}
- if (t != 0) {
- t->mLock.unlock();
- }
}
void AudioTrack::stop()
@@ -406,9 +402,6 @@
sp<AudioTrackThread> t = mAudioTrackThread;
ALOGV("stop %p", this);
- if (t != 0) {
- t->mLock.lock();
- }
AutoMutex lock(mLock);
if (mActive) {
@@ -434,9 +427,6 @@
}
}
- if (t != 0) {
- t->mLock.unlock();
- }
}
bool AudioTrack::stopped() const
@@ -506,7 +496,7 @@
return NO_ERROR;
}
-void AudioTrack::getVolume(float* left, float* right)
+void AudioTrack::getVolume(float* left, float* right) const
{
if (left != NULL) {
*left = mVolume[LEFT];
@@ -531,7 +521,7 @@
return NO_ERROR;
}
-void AudioTrack::getAuxEffectSendLevel(float* level)
+void AudioTrack::getAuxEffectSendLevel(float* level) const
{
if (level != NULL) {
*level = mSendLevel;
@@ -553,7 +543,7 @@
return NO_ERROR;
}
-uint32_t AudioTrack::getSampleRate()
+uint32_t AudioTrack::getSampleRate() const
{
AutoMutex lock(mLock);
return mCblk->sampleRate;
@@ -601,7 +591,7 @@
return NO_ERROR;
}
-status_t AudioTrack::getLoop(uint32_t *loopStart, uint32_t *loopEnd, int *loopCount)
+status_t AudioTrack::getLoop(uint32_t *loopStart, uint32_t *loopEnd, int *loopCount) const
{
AutoMutex lock(mLock);
if (loopStart != NULL) {
@@ -631,7 +621,7 @@
return NO_ERROR;
}
-status_t AudioTrack::getMarkerPosition(uint32_t *marker)
+status_t AudioTrack::getMarkerPosition(uint32_t *marker) const
{
if (marker == NULL) return BAD_VALUE;
@@ -652,7 +642,7 @@
return NO_ERROR;
}
-status_t AudioTrack::getPositionUpdatePeriod(uint32_t *updatePeriod)
+status_t AudioTrack::getPositionUpdatePeriod(uint32_t *updatePeriod) const
{
if (updatePeriod == NULL) return BAD_VALUE;
@@ -712,7 +702,7 @@
mCblk->sampleRate, mFormat, mChannelMask, (audio_policy_output_flags_t)mFlags);
}
-int AudioTrack::getSessionId()
+int AudioTrack::getSessionId() const
{
return mSessionId;
}
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index fc5520f..4507e5d 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -89,7 +89,7 @@
int frameCount,
uint32_t flags,
const sp<IMemory>& sharedBuffer,
- int output,
+ audio_io_handle_t output,
int *sessionId,
status_t *status)
{
@@ -104,7 +104,7 @@
data.writeInt32(frameCount);
data.writeInt32(flags);
data.writeStrongBinder(sharedBuffer->asBinder());
- data.writeInt32(output);
+ data.writeInt32((int32_t) output);
int lSessionId = 0;
if (sessionId != NULL) {
lSessionId = *sessionId;
@@ -129,7 +129,7 @@
virtual sp<IAudioRecord> openRecord(
pid_t pid,
- int input,
+ audio_io_handle_t input,
uint32_t sampleRate,
audio_format_t format,
uint32_t channelMask,
@@ -142,7 +142,7 @@
sp<IAudioRecord> record;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
data.writeInt32(pid);
- data.writeInt32(input);
+ data.writeInt32((int32_t) input);
data.writeInt32(sampleRate);
data.writeInt32(format);
data.writeInt32(channelMask);
@@ -170,47 +170,47 @@
return record;
}
- virtual uint32_t sampleRate(int output) const
+ virtual uint32_t sampleRate(audio_io_handle_t output) const
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
- data.writeInt32(output);
+ data.writeInt32((int32_t) output);
remote()->transact(SAMPLE_RATE, data, &reply);
return reply.readInt32();
}
- virtual int channelCount(int output) const
+ virtual int channelCount(audio_io_handle_t output) const
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
- data.writeInt32(output);
+ data.writeInt32((int32_t) output);
remote()->transact(CHANNEL_COUNT, data, &reply);
return reply.readInt32();
}
- virtual audio_format_t format(int output) const
+ virtual audio_format_t format(audio_io_handle_t output) const
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
- data.writeInt32(output);
+ data.writeInt32((int32_t) output);
remote()->transact(FORMAT, data, &reply);
return (audio_format_t) reply.readInt32();
}
- virtual size_t frameCount(int output) const
+ virtual size_t frameCount(audio_io_handle_t output) const
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
- data.writeInt32(output);
+ data.writeInt32((int32_t) output);
remote()->transact(FRAME_COUNT, data, &reply);
return reply.readInt32();
}
- virtual uint32_t latency(int output) const
+ virtual uint32_t latency(audio_io_handle_t output) const
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
- data.writeInt32(output);
+ data.writeInt32((int32_t) output);
remote()->transact(LATENCY, data, &reply);
return reply.readInt32();
}
@@ -249,13 +249,14 @@
return reply.readInt32();
}
- virtual status_t setStreamVolume(audio_stream_type_t stream, float value, int output)
+ virtual status_t setStreamVolume(audio_stream_type_t stream, float value,
+ audio_io_handle_t output)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
data.writeInt32((int32_t) stream);
data.writeFloat(value);
- data.writeInt32(output);
+ data.writeInt32((int32_t) output);
remote()->transact(SET_STREAM_VOLUME, data, &reply);
return reply.readInt32();
}
@@ -270,12 +271,12 @@
return reply.readInt32();
}
- virtual float streamVolume(audio_stream_type_t stream, int output) const
+ virtual float streamVolume(audio_stream_type_t stream, audio_io_handle_t output) const
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
data.writeInt32((int32_t) stream);
- data.writeInt32(output);
+ data.writeInt32((int32_t) output);
remote()->transact(STREAM_VOLUME, data, &reply);
return reply.readFloat();
}
@@ -315,21 +316,21 @@
return reply.readInt32();
}
- virtual status_t setParameters(int ioHandle, const String8& keyValuePairs)
+ virtual status_t setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
- data.writeInt32(ioHandle);
+ data.writeInt32((int32_t) ioHandle);
data.writeString8(keyValuePairs);
remote()->transact(SET_PARAMETERS, data, &reply);
return reply.readInt32();
}
- virtual String8 getParameters(int ioHandle, const String8& keys)
+ virtual String8 getParameters(audio_io_handle_t ioHandle, const String8& keys) const
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
- data.writeInt32(ioHandle);
+ data.writeInt32((int32_t) ioHandle);
data.writeString8(keys);
remote()->transact(GET_PARAMETERS, data, &reply);
return reply.readString8();
@@ -343,7 +344,7 @@
remote()->transact(REGISTER_CLIENT, data, &reply);
}
- virtual size_t getInputBufferSize(uint32_t sampleRate, audio_format_t format, int channelCount)
+ virtual size_t getInputBufferSize(uint32_t sampleRate, audio_format_t format, int channelCount) const
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
@@ -354,7 +355,7 @@
return reply.readInt32();
}
- virtual int openOutput(uint32_t *pDevices,
+ virtual audio_io_handle_t openOutput(uint32_t *pDevices,
uint32_t *pSamplingRate,
audio_format_t *pFormat,
uint32_t *pChannels,
@@ -376,8 +377,8 @@
data.writeInt32(latency);
data.writeInt32(flags);
remote()->transact(OPEN_OUTPUT, data, &reply);
- int output = reply.readInt32();
- ALOGV("openOutput() returned output, %p", output);
+ audio_io_handle_t output = (audio_io_handle_t) reply.readInt32();
+ ALOGV("openOutput() returned output, %d", output);
devices = reply.readInt32();
if (pDevices) *pDevices = devices;
samplingRate = reply.readInt32();
@@ -391,44 +392,45 @@
return output;
}
- virtual int openDuplicateOutput(int output1, int output2)
+ virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1,
+ audio_io_handle_t output2)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
- data.writeInt32(output1);
- data.writeInt32(output2);
+ data.writeInt32((int32_t) output1);
+ data.writeInt32((int32_t) output2);
remote()->transact(OPEN_DUPLICATE_OUTPUT, data, &reply);
- return reply.readInt32();
+ return (audio_io_handle_t) reply.readInt32();
}
- virtual status_t closeOutput(int output)
+ virtual status_t closeOutput(audio_io_handle_t output)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
- data.writeInt32(output);
+ data.writeInt32((int32_t) output);
remote()->transact(CLOSE_OUTPUT, data, &reply);
return reply.readInt32();
}
- virtual status_t suspendOutput(int output)
+ virtual status_t suspendOutput(audio_io_handle_t output)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
- data.writeInt32(output);
+ data.writeInt32((int32_t) output);
remote()->transact(SUSPEND_OUTPUT, data, &reply);
return reply.readInt32();
}
- virtual status_t restoreOutput(int output)
+ virtual status_t restoreOutput(audio_io_handle_t output)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
- data.writeInt32(output);
+ data.writeInt32((int32_t) output);
remote()->transact(RESTORE_OUTPUT, data, &reply);
return reply.readInt32();
}
- virtual int openInput(uint32_t *pDevices,
+ virtual audio_io_handle_t openInput(uint32_t *pDevices,
uint32_t *pSamplingRate,
audio_format_t *pFormat,
uint32_t *pChannels,
@@ -447,7 +449,7 @@
data.writeInt32(channels);
data.writeInt32((int32_t) acoustics);
remote()->transact(OPEN_INPUT, data, &reply);
- int input = reply.readInt32();
+ audio_io_handle_t input = (audio_io_handle_t) reply.readInt32();
devices = reply.readInt32();
if (pDevices) *pDevices = devices;
samplingRate = reply.readInt32();
@@ -468,12 +470,12 @@
return reply.readInt32();
}
- virtual status_t setStreamOutput(audio_stream_type_t stream, int output)
+ virtual status_t setStreamOutput(audio_stream_type_t stream, audio_io_handle_t output)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
data.writeInt32((int32_t) stream);
- data.writeInt32(output);
+ data.writeInt32((int32_t) output);
remote()->transact(SET_STREAM_OUTPUT, data, &reply);
return reply.readInt32();
}
@@ -487,11 +489,12 @@
return reply.readInt32();
}
- virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, int output)
+ virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames,
+ audio_io_handle_t output) const
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
- data.writeInt32(output);
+ data.writeInt32((int32_t) output);
remote()->transact(GET_RENDER_POSITION, data, &reply);
status_t status = reply.readInt32();
if (status == NO_ERROR) {
@@ -507,11 +510,11 @@
return status;
}
- virtual unsigned int getInputFramesLost(int ioHandle)
+ virtual unsigned int getInputFramesLost(audio_io_handle_t ioHandle) const
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
- data.writeInt32(ioHandle);
+ data.writeInt32((int32_t) ioHandle);
remote()->transact(GET_INPUT_FRAMES_LOST, data, &reply);
return reply.readInt32();
}
@@ -544,7 +547,7 @@
remote()->transact(RELEASE_AUDIO_SESSION_ID, data, &reply);
}
- virtual status_t queryNumberEffects(uint32_t *numEffects)
+ virtual status_t queryNumberEffects(uint32_t *numEffects) const
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
@@ -556,13 +559,13 @@
if (status != NO_ERROR) {
return status;
}
- if (numEffects) {
+ if (numEffects != NULL) {
*numEffects = (uint32_t)reply.readInt32();
}
return NO_ERROR;
}
- virtual status_t queryEffect(uint32_t index, effect_descriptor_t *pDescriptor)
+ virtual status_t queryEffect(uint32_t index, effect_descriptor_t *pDescriptor) const
{
if (pDescriptor == NULL) {
return BAD_VALUE;
@@ -582,7 +585,8 @@
return NO_ERROR;
}
- virtual status_t getEffectDescriptor(effect_uuid_t *pUuid, effect_descriptor_t *pDescriptor)
+ virtual status_t getEffectDescriptor(const effect_uuid_t *pUuid,
+ effect_descriptor_t *pDescriptor) const
{
if (pUuid == NULL || pDescriptor == NULL) {
return BAD_VALUE;
@@ -606,7 +610,7 @@
effect_descriptor_t *pDesc,
const sp<IEffectClient>& client,
int32_t priority,
- int output,
+ audio_io_handle_t output,
int sessionId,
status_t *status,
int *id,
@@ -627,7 +631,7 @@
data.write(pDesc, sizeof(effect_descriptor_t));
data.writeStrongBinder(client->asBinder());
data.writeInt32(priority);
- data.writeInt32(output);
+ data.writeInt32((int32_t) output);
data.writeInt32(sessionId);
status_t lStatus = remote()->transact(CREATE_EFFECT, data, &reply);
@@ -653,13 +657,14 @@
return effect;
}
- virtual status_t moveEffects(int session, int srcOutput, int dstOutput)
+ virtual status_t moveEffects(int session, audio_io_handle_t srcOutput,
+ audio_io_handle_t dstOutput)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
data.writeInt32(session);
- data.writeInt32(srcOutput);
- data.writeInt32(dstOutput);
+ data.writeInt32((int32_t) srcOutput);
+ data.writeInt32((int32_t) dstOutput);
remote()->transact(MOVE_EFFECTS, data, &reply);
return reply.readInt32();
}
@@ -683,7 +688,7 @@
size_t bufferCount = data.readInt32();
uint32_t flags = data.readInt32();
sp<IMemory> buffer = interface_cast<IMemory>(data.readStrongBinder());
- int output = data.readInt32();
+ audio_io_handle_t output = (audio_io_handle_t) data.readInt32();
int sessionId = data.readInt32();
status_t status;
sp<IAudioTrack> track = createTrack(pid,
@@ -697,7 +702,7 @@
case OPEN_RECORD: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
pid_t pid = data.readInt32();
- int input = data.readInt32();
+ audio_io_handle_t input = (audio_io_handle_t) data.readInt32();
uint32_t sampleRate = data.readInt32();
audio_format_t format = (audio_format_t) data.readInt32();
int channelCount = data.readInt32();
@@ -714,27 +719,27 @@
} break;
case SAMPLE_RATE: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- reply->writeInt32( sampleRate(data.readInt32()) );
+ reply->writeInt32( sampleRate((audio_io_handle_t) data.readInt32()) );
return NO_ERROR;
} break;
case CHANNEL_COUNT: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- reply->writeInt32( channelCount(data.readInt32()) );
+ reply->writeInt32( channelCount((audio_io_handle_t) data.readInt32()) );
return NO_ERROR;
} break;
case FORMAT: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- reply->writeInt32( format(data.readInt32()) );
+ reply->writeInt32( format((audio_io_handle_t) data.readInt32()) );
return NO_ERROR;
} break;
case FRAME_COUNT: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- reply->writeInt32( frameCount(data.readInt32()) );
+ reply->writeInt32( frameCount((audio_io_handle_t) data.readInt32()) );
return NO_ERROR;
} break;
case LATENCY: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- reply->writeInt32( latency(data.readInt32()) );
+ reply->writeInt32( latency((audio_io_handle_t) data.readInt32()) );
return NO_ERROR;
} break;
case SET_MASTER_VOLUME: {
@@ -761,7 +766,7 @@
CHECK_INTERFACE(IAudioFlinger, data, reply);
int stream = data.readInt32();
float volume = data.readFloat();
- int output = data.readInt32();
+ audio_io_handle_t output = (audio_io_handle_t) data.readInt32();
reply->writeInt32( setStreamVolume((audio_stream_type_t) stream, volume, output) );
return NO_ERROR;
} break;
@@ -803,14 +808,14 @@
} break;
case SET_PARAMETERS: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- int ioHandle = data.readInt32();
+ audio_io_handle_t ioHandle = (audio_io_handle_t) data.readInt32();
String8 keyValuePairs(data.readString8());
reply->writeInt32(setParameters(ioHandle, keyValuePairs));
return NO_ERROR;
} break;
case GET_PARAMETERS: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- int ioHandle = data.readInt32();
+ audio_io_handle_t ioHandle = (audio_io_handle_t) data.readInt32();
String8 keys(data.readString8());
reply->writeString8(getParameters(ioHandle, keys));
return NO_ERROR;
@@ -838,14 +843,14 @@
uint32_t channels = data.readInt32();
uint32_t latency = data.readInt32();
uint32_t flags = data.readInt32();
- int output = openOutput(&devices,
+ audio_io_handle_t output = openOutput(&devices,
&samplingRate,
&format,
&channels,
&latency,
flags);
ALOGV("OPEN_OUTPUT output, %p", output);
- reply->writeInt32(output);
+ reply->writeInt32((int32_t) output);
reply->writeInt32(devices);
reply->writeInt32(samplingRate);
reply->writeInt32(format);
@@ -855,24 +860,24 @@
} break;
case OPEN_DUPLICATE_OUTPUT: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- int output1 = data.readInt32();
- int output2 = data.readInt32();
- reply->writeInt32(openDuplicateOutput(output1, output2));
+ audio_io_handle_t output1 = (audio_io_handle_t) data.readInt32();
+ audio_io_handle_t output2 = (audio_io_handle_t) data.readInt32();
+ reply->writeInt32((int32_t) openDuplicateOutput(output1, output2));
return NO_ERROR;
} break;
case CLOSE_OUTPUT: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- reply->writeInt32(closeOutput(data.readInt32()));
+ reply->writeInt32(closeOutput((audio_io_handle_t) data.readInt32()));
return NO_ERROR;
} break;
case SUSPEND_OUTPUT: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- reply->writeInt32(suspendOutput(data.readInt32()));
+ reply->writeInt32(suspendOutput((audio_io_handle_t) data.readInt32()));
return NO_ERROR;
} break;
case RESTORE_OUTPUT: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- reply->writeInt32(restoreOutput(data.readInt32()));
+ reply->writeInt32(restoreOutput((audio_io_handle_t) data.readInt32()));
return NO_ERROR;
} break;
case OPEN_INPUT: {
@@ -883,12 +888,12 @@
uint32_t channels = data.readInt32();
audio_in_acoustics_t acoustics = (audio_in_acoustics_t) data.readInt32();
- int input = openInput(&devices,
+ audio_io_handle_t input = openInput(&devices,
&samplingRate,
&format,
&channels,
acoustics);
- reply->writeInt32(input);
+ reply->writeInt32((int32_t) input);
reply->writeInt32(devices);
reply->writeInt32(samplingRate);
reply->writeInt32(format);
@@ -897,13 +902,13 @@
} break;
case CLOSE_INPUT: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- reply->writeInt32(closeInput(data.readInt32()));
+ reply->writeInt32(closeInput((audio_io_handle_t) data.readInt32()));
return NO_ERROR;
} break;
case SET_STREAM_OUTPUT: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
uint32_t stream = data.readInt32();
- int output = data.readInt32();
+ audio_io_handle_t output = (audio_io_handle_t) data.readInt32();
reply->writeInt32(setStreamOutput((audio_stream_type_t) stream, output));
return NO_ERROR;
} break;
@@ -915,7 +920,7 @@
} break;
case GET_RENDER_POSITION: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- int output = data.readInt32();
+ audio_io_handle_t output = (audio_io_handle_t) data.readInt32();
uint32_t halFrames;
uint32_t dspFrames;
status_t status = getRenderPosition(&halFrames, &dspFrames, output);
@@ -928,7 +933,7 @@
}
case GET_INPUT_FRAMES_LOST: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- int ioHandle = data.readInt32();
+ audio_io_handle_t ioHandle = (audio_io_handle_t) data.readInt32();
reply->writeInt32(getInputFramesLost(ioHandle));
return NO_ERROR;
} break;
@@ -988,7 +993,7 @@
data.read(&desc, sizeof(effect_descriptor_t));
sp<IEffectClient> client = interface_cast<IEffectClient>(data.readStrongBinder());
int32_t priority = data.readInt32();
- int output = data.readInt32();
+ audio_io_handle_t output = (audio_io_handle_t) data.readInt32();
int sessionId = data.readInt32();
status_t status;
int id;
@@ -1005,8 +1010,8 @@
case MOVE_EFFECTS: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
int session = data.readInt32();
- int srcOutput = data.readInt32();
- int dstOutput = data.readInt32();
+ audio_io_handle_t srcOutput = (audio_io_handle_t) data.readInt32();
+ audio_io_handle_t dstOutput = (audio_io_handle_t) data.readInt32();
reply->writeInt32(moveEffects(session, srcOutput, dstOutput));
return NO_ERROR;
} break;
diff --git a/media/libmedia/IAudioFlingerClient.cpp b/media/libmedia/IAudioFlingerClient.cpp
index 9458bc0..ce28b33 100644
--- a/media/libmedia/IAudioFlingerClient.cpp
+++ b/media/libmedia/IAudioFlingerClient.cpp
@@ -39,12 +39,12 @@
{
}
- void ioConfigChanged(int event, int ioHandle, void *param2)
+ void ioConfigChanged(int event, audio_io_handle_t ioHandle, void *param2)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlingerClient::getInterfaceDescriptor());
data.writeInt32(event);
- data.writeInt32(ioHandle);
+ data.writeInt32((int32_t) ioHandle);
if (event == AudioSystem::STREAM_CONFIG_CHANGED) {
uint32_t stream = *(uint32_t *)param2;
ALOGV("ioConfigChanged stream %d", stream);
@@ -72,7 +72,7 @@
case IO_CONFIG_CHANGED: {
CHECK_INTERFACE(IAudioFlingerClient, data, reply);
int event = data.readInt32();
- int ioHandle = data.readInt32();
+ audio_io_handle_t ioHandle = (audio_io_handle_t) data.readInt32();
void *param2 = NULL;
AudioSystem::OutputDescriptor desc;
uint32_t stream;
diff --git a/media/libmedia/JetPlayer.cpp b/media/libmedia/JetPlayer.cpp
index 8456db5..6cb5b82 100644
--- a/media/libmedia/JetPlayer.cpp
+++ b/media/libmedia/JetPlayer.cpp
@@ -246,14 +246,12 @@
}//while (1)
threadExit:
- if (mAudioTrack) {
+ if (mAudioTrack != NULL) {
mAudioTrack->stop();
mAudioTrack->flush();
}
- if (mAudioBuffer) {
- delete [] mAudioBuffer;
- mAudioBuffer = NULL;
- }
+ delete [] mAudioBuffer;
+ mAudioBuffer = NULL;
mMutex.lock();
mTid = -1;
mCondition.signal();
diff --git a/media/libmedia/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp
index c905762..93ddca8 100644
--- a/media/libmedia/MediaProfiles.cpp
+++ b/media/libmedia/MediaProfiles.cpp
@@ -25,7 +25,7 @@
#include <cutils/properties.h>
#include <expat.h>
#include <media/MediaProfiles.h>
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/openmax/OMX_Video.h>
namespace android {
@@ -349,7 +349,7 @@
{
CHECK(!strcmp("quality", atts[0]));
int quality = atoi(atts[1]);
- ALOGV("%s: cameraId=%d, quality=%d\n", __func__, cameraId, quality);
+ ALOGV("%s: cameraId=%d, quality=%d", __func__, cameraId, quality);
ImageEncodingQualityLevels *levels = findImageEncodingQualityLevels(cameraId);
if (levels == NULL) {
diff --git a/media/libmedia/MediaScanner.cpp b/media/libmedia/MediaScanner.cpp
index 79cab74a..73d4519 100644
--- a/media/libmedia/MediaScanner.cpp
+++ b/media/libmedia/MediaScanner.cpp
@@ -143,7 +143,7 @@
if (pathRemaining >= 8 /* strlen(".nomedia") */ ) {
strcpy(fileSpot, ".nomedia");
if (access(path, F_OK) == 0) {
- ALOGV("found .nomedia, setting noMedia flag\n");
+ ALOGV("found .nomedia, setting noMedia flag");
noMedia = true;
}
diff --git a/media/libmedia/MediaScannerClient.cpp b/media/libmedia/MediaScannerClient.cpp
index 9fe1820..cdfd477 100644
--- a/media/libmedia/MediaScannerClient.cpp
+++ b/media/libmedia/MediaScannerClient.cpp
@@ -142,12 +142,12 @@
UConverter *conv = ucnv_open(enc, &status);
if (U_FAILURE(status)) {
- ALOGE("could not create UConverter for %s\n", enc);
+ ALOGE("could not create UConverter for %s", enc);
return;
}
UConverter *utf8Conv = ucnv_open("UTF-8", &status);
if (U_FAILURE(status)) {
- ALOGE("could not create UConverter for UTF-8\n");
+ ALOGE("could not create UConverter for UTF-8");
ucnv_close(conv);
return;
}
@@ -181,7 +181,7 @@
ucnv_convertEx(utf8Conv, conv, &target, target + targetLength,
&source, (const char *)dest, NULL, NULL, NULL, NULL, TRUE, TRUE, &status);
if (U_FAILURE(status)) {
- ALOGE("ucnv_convertEx failed: %d\n", status);
+ ALOGE("ucnv_convertEx failed: %d", status);
mValues->setEntry(i, "???");
} else {
// zero terminate
diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
index e6e989d..6cb10aa 100644
--- a/media/libmedia/ToneGenerator.cpp
+++ b/media/libmedia/ToneGenerator.cpp
@@ -800,7 +800,7 @@
////////////////////////////////////////////////////////////////////////////////
ToneGenerator::ToneGenerator(audio_stream_type_t streamType, float volume, bool threadCanCallJava) {
- ALOGV("ToneGenerator constructor: streamType=%d, volume=%f\n", streamType, volume);
+ ALOGV("ToneGenerator constructor: streamType=%d, volume=%f", streamType, volume);
mState = TONE_IDLE;
@@ -829,9 +829,9 @@
}
if (initAudioTrack()) {
- ALOGV("ToneGenerator INIT OK, time: %d\n", (unsigned int)(systemTime()/1000000));
+ ALOGV("ToneGenerator INIT OK, time: %d", (unsigned int)(systemTime()/1000000));
} else {
- ALOGV("!!!ToneGenerator INIT FAILED!!!\n");
+ ALOGV("!!!ToneGenerator INIT FAILED!!!");
}
}
@@ -853,11 +853,11 @@
//
////////////////////////////////////////////////////////////////////////////////
ToneGenerator::~ToneGenerator() {
- ALOGV("ToneGenerator destructor\n");
+ ALOGV("ToneGenerator destructor");
if (mpAudioTrack != NULL) {
stopTone();
- ALOGV("Delete Track: %p\n", mpAudioTrack);
+ ALOGV("Delete Track: %p", mpAudioTrack);
delete mpAudioTrack;
}
}
@@ -892,7 +892,7 @@
}
}
- ALOGV("startTone\n");
+ ALOGV("startTone");
mLock.lock();
@@ -915,7 +915,7 @@
if (mState == TONE_INIT) {
if (prepareWave()) {
- ALOGV("Immediate start, time %d\n", (unsigned int)(systemTime()/1000000));
+ ALOGV("Immediate start, time %d", (unsigned int)(systemTime()/1000000));
lResult = true;
mState = TONE_STARTING;
mLock.unlock();
@@ -934,7 +934,7 @@
mState = TONE_IDLE;
}
} else {
- ALOGV("Delayed start\n");
+ ALOGV("Delayed start");
mState = TONE_RESTARTING;
lStatus = mWaitCbkCond.waitRelative(mLock, seconds(3));
if (lStatus == NO_ERROR) {
@@ -949,8 +949,8 @@
}
mLock.unlock();
- ALOGV_IF(lResult, "Tone started, time %d\n", (unsigned int)(systemTime()/1000000));
- ALOGW_IF(!lResult, "Tone start failed!!!, time %d\n", (unsigned int)(systemTime()/1000000));
+ ALOGV_IF(lResult, "Tone started, time %d", (unsigned int)(systemTime()/1000000));
+ ALOGW_IF(!lResult, "Tone start failed!!!, time %d", (unsigned int)(systemTime()/1000000));
return lResult;
}
@@ -1017,7 +1017,7 @@
// Open audio track in mono, PCM 16bit, default sampling rate, default buffer size
mpAudioTrack = new AudioTrack();
- ALOGV("Create Track: %p\n", mpAudioTrack);
+ ALOGV("Create Track: %p", mpAudioTrack);
mpAudioTrack->set(mStreamType,
0,
@@ -1045,8 +1045,8 @@
initAudioTrack_exit:
// Cleanup
- if (mpAudioTrack) {
- ALOGV("Delete Track I: %p\n", mpAudioTrack);
+ if (mpAudioTrack != NULL) {
+ ALOGV("Delete Track I: %p", mpAudioTrack);
delete mpAudioTrack;
mpAudioTrack = NULL;
}
@@ -1141,7 +1141,7 @@
if (lpToneGen->mTotalSmp > lpToneGen->mNextSegSmp) {
// Time to go to next sequence segment
- ALOGV("End Segment, time: %d\n", (unsigned int)(systemTime()/1000000));
+ ALOGV("End Segment, time: %d", (unsigned int)(systemTime()/1000000));
lGenSmp = lReqSmp;
@@ -1156,13 +1156,13 @@
lpWaveGen->getSamples(lpOut, lGenSmp, lWaveCmd);
lFrequency = lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[++lFreqIdx];
}
- ALOGV("ON->OFF, lGenSmp: %d, lReqSmp: %d\n", lGenSmp, lReqSmp);
+ ALOGV("ON->OFF, lGenSmp: %d, lReqSmp: %d", lGenSmp, lReqSmp);
}
// check if we need to loop and loop for the reqd times
if (lpToneDesc->segments[lpToneGen->mCurSegment].loopCnt) {
if (lpToneGen->mLoopCounter < lpToneDesc->segments[lpToneGen->mCurSegment].loopCnt) {
- ALOGV ("in if loop loopCnt(%d) loopctr(%d), CurSeg(%d) \n",
+ ALOGV ("in if loop loopCnt(%d) loopctr(%d), CurSeg(%d)",
lpToneDesc->segments[lpToneGen->mCurSegment].loopCnt,
lpToneGen->mLoopCounter,
lpToneGen->mCurSegment);
@@ -1172,14 +1172,14 @@
// completed loop. go to next segment
lpToneGen->mLoopCounter = 0;
lpToneGen->mCurSegment++;
- ALOGV ("in else loop loopCnt(%d) loopctr(%d), CurSeg(%d) \n",
+ ALOGV ("in else loop loopCnt(%d) loopctr(%d), CurSeg(%d)",
lpToneDesc->segments[lpToneGen->mCurSegment].loopCnt,
lpToneGen->mLoopCounter,
lpToneGen->mCurSegment);
}
} else {
lpToneGen->mCurSegment++;
- ALOGV ("Goto next seg loopCnt(%d) loopctr(%d), CurSeg(%d) \n",
+ ALOGV ("Goto next seg loopCnt(%d) loopctr(%d), CurSeg(%d)",
lpToneDesc->segments[lpToneGen->mCurSegment].loopCnt,
lpToneGen->mLoopCounter,
lpToneGen->mCurSegment);
@@ -1188,32 +1188,32 @@
// Handle loop if last segment reached
if (lpToneDesc->segments[lpToneGen->mCurSegment].duration == 0) {
- ALOGV("Last Seg: %d\n", lpToneGen->mCurSegment);
+ ALOGV("Last Seg: %d", lpToneGen->mCurSegment);
// Pre increment loop count and restart if total count not reached. Stop sequence otherwise
if (++lpToneGen->mCurCount <= lpToneDesc->repeatCnt) {
- ALOGV("Repeating Count: %d\n", lpToneGen->mCurCount);
+ ALOGV("Repeating Count: %d", lpToneGen->mCurCount);
lpToneGen->mCurSegment = lpToneDesc->repeatSegment;
if (lpToneDesc->segments[lpToneDesc->repeatSegment].waveFreq[0] != 0) {
lWaveCmd = WaveGenerator::WAVEGEN_START;
}
- ALOGV("New segment %d, Next Time: %d\n", lpToneGen->mCurSegment,
+ ALOGV("New segment %d, Next Time: %d", lpToneGen->mCurSegment,
(lpToneGen->mNextSegSmp*1000)/lpToneGen->mSamplingRate);
} else {
lGenSmp = 0;
- ALOGV("End repeat, time: %d\n", (unsigned int)(systemTime()/1000000));
+ ALOGV("End repeat, time: %d", (unsigned int)(systemTime()/1000000));
}
} else {
- ALOGV("New segment %d, Next Time: %d\n", lpToneGen->mCurSegment,
+ ALOGV("New segment %d, Next Time: %d", lpToneGen->mCurSegment,
(lpToneGen->mNextSegSmp*1000)/lpToneGen->mSamplingRate);
if (lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[0] != 0) {
// If next segment is not silent, OFF -> ON transition : reset wave generator
lWaveCmd = WaveGenerator::WAVEGEN_START;
- ALOGV("OFF->ON, lGenSmp: %d, lReqSmp: %d\n", lGenSmp, lReqSmp);
+ ALOGV("OFF->ON, lGenSmp: %d, lReqSmp: %d", lGenSmp, lReqSmp);
} else {
lGenSmp = 0;
}
@@ -1251,13 +1251,13 @@
switch (lpToneGen->mState) {
case TONE_RESTARTING:
- ALOGV("Cbk restarting track\n");
+ ALOGV("Cbk restarting track");
if (lpToneGen->prepareWave()) {
lpToneGen->mState = TONE_STARTING;
// must reload lpToneDesc as prepareWave() may change mpToneDesc
lpToneDesc = lpToneGen->mpToneDesc;
} else {
- ALOGW("Cbk restarting prepareWave() failed\n");
+ ALOGW("Cbk restarting prepareWave() failed");
lpToneGen->mState = TONE_IDLE;
lpToneGen->mpAudioTrack->stop();
// Force loop exit
@@ -1266,14 +1266,14 @@
lSignal = true;
break;
case TONE_STOPPING:
- ALOGV("Cbk Stopping\n");
+ ALOGV("Cbk Stopping");
lpToneGen->mState = TONE_STOPPED;
// Force loop exit
lNumSmp = 0;
break;
case TONE_STOPPED:
lpToneGen->mState = TONE_INIT;
- ALOGV("Cbk Stopped track\n");
+ ALOGV("Cbk Stopped track");
lpToneGen->mpAudioTrack->stop();
// Force loop exit
lNumSmp = 0;
@@ -1281,7 +1281,7 @@
lSignal = true;
break;
case TONE_STARTING:
- ALOGV("Cbk starting track\n");
+ ALOGV("Cbk starting track");
lpToneGen->mState = TONE_PLAYING;
lSignal = true;
break;
@@ -1491,7 +1491,7 @@
d0 = 32767;
mA1_Q14 = (short) d0;
- ALOGV("WaveGenerator init, mA1_Q14: %d, mS2_0: %d, mAmplitude_Q15: %d\n",
+ ALOGV("WaveGenerator init, mA1_Q14: %d, mS2_0: %d, mAmplitude_Q15: %d",
mA1_Q14, mS2_0, mAmplitude_Q15);
}
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 4632016..fe519b0 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -24,6 +24,7 @@
#include <binder/IServiceManager.h>
#include <media/IMediaPlayerService.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/AudioSource.h>
#include <media/stagefright/AMRWriter.h>
#include <media/stagefright/AACWriter.h>
@@ -31,7 +32,6 @@
#include <media/stagefright/CameraSourceTimeLapse.h>
#include <media/stagefright/MPEG2TSWriter.h>
#include <media/stagefright/MPEG4Writer.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/OMXClient.h>
@@ -241,8 +241,8 @@
status_t StagefrightRecorder::setOutputFile(int fd, int64_t offset, int64_t length) {
ALOGV("setOutputFile: %d, %lld, %lld", fd, offset, length);
// These don't make any sense, do they?
- CHECK_EQ(offset, 0);
- CHECK_EQ(length, 0);
+ CHECK_EQ(offset, 0ll);
+ CHECK_EQ(length, 0ll);
if (fd < 0) {
ALOGE("Invalid file descriptor: %d", fd);
@@ -734,7 +734,7 @@
}
status_t StagefrightRecorder::start() {
- CHECK(mOutputFd >= 0);
+ CHECK_GE(mOutputFd, 0);
if (mWriter != NULL) {
ALOGE("File writer is not avaialble");
@@ -837,7 +837,7 @@
}
OMXClient client;
- CHECK_EQ(client.connect(), OK);
+ CHECK_EQ(client.connect(), (status_t)OK);
sp<MediaSource> audioEncoder =
OMXCodec::Create(client.interface(), encMeta,
@@ -850,9 +850,9 @@
status_t StagefrightRecorder::startAACRecording() {
// FIXME:
// Add support for OUTPUT_FORMAT_AAC_ADIF
- CHECK(mOutputFormat == OUTPUT_FORMAT_AAC_ADTS);
+ CHECK_EQ(mOutputFormat, OUTPUT_FORMAT_AAC_ADTS);
- CHECK(mAudioEncoder == AUDIO_ENCODER_AAC);
+ CHECK_EQ(mAudioEncoder, AUDIO_ENCODER_AAC);
CHECK(mAudioSource != AUDIO_SOURCE_CNT);
mWriter = new AACWriter(mOutputFd);
@@ -1386,7 +1386,7 @@
}
OMXClient client;
- CHECK_EQ(client.connect(), OK);
+ CHECK_EQ(client.connect(), (status_t)OK);
uint32_t encoder_flags = 0;
if (mIsMetaDataStoredInVideoBuffers) {
diff --git a/media/libstagefright/AACExtractor.cpp b/media/libstagefright/AACExtractor.cpp
index 33f22f2..4d1072f 100644
--- a/media/libstagefright/AACExtractor.cpp
+++ b/media/libstagefright/AACExtractor.cpp
@@ -23,9 +23,9 @@
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaSource.h>
diff --git a/media/libstagefright/AMRExtractor.cpp b/media/libstagefright/AMRExtractor.cpp
index 5a28347..03dcbf9 100644
--- a/media/libstagefright/AMRExtractor.cpp
+++ b/media/libstagefright/AMRExtractor.cpp
@@ -20,9 +20,9 @@
#include "include/AMRExtractor.h"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaSource.h>
diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp
index 59b4ca7..ca85640 100644
--- a/media/libstagefright/AMRWriter.cpp
+++ b/media/libstagefright/AMRWriter.cpp
@@ -14,9 +14,9 @@
* limitations under the License.
*/
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/AMRWriter.h>
#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaSource.h>
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 8073af8..85b7979 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -1360,7 +1360,7 @@
mAudioTrack = source;
}
-void AwesomePlayer::addTextSource(sp<MediaSource> source) {
+void AwesomePlayer::addTextSource(const sp<MediaSource>& source) {
Mutex::Autolock autoLock(mTimedTextLock);
CHECK(source != NULL);
@@ -1609,7 +1609,7 @@
mSeekTimeUs,
mSeeking == SEEK_VIDEO_ONLY
? MediaSource::ReadOptions::SEEK_NEXT_SYNC
- : MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
+ : MediaSource::ReadOptions::SEEK_CLOSEST);
}
for (;;) {
status_t err = mVideoSource->read(&mVideoBuffer, &options);
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 228659c..ed1d5f4 100755
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -20,8 +20,8 @@
#include <OMX_Component.h>
#include <binder/IPCThreadState.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/CameraSource.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
@@ -114,7 +114,7 @@
ALOGE("Uknown color format (%s), please add it to "
"CameraSource::getColorFormat", colorFormat);
- CHECK_EQ(0, "Unknown color format");
+ CHECK(!"Unknown color format");
}
CameraSource *CameraSource::Create() {
@@ -517,7 +517,7 @@
// This CHECK is good, since we just passed the lock/unlock
// check earlier by calling mCamera->setParameters().
- CHECK_EQ(OK, mCamera->setPreviewDisplay(mSurface));
+ CHECK_EQ((status_t)OK, mCamera->setPreviewDisplay(mSurface));
// By default, do not store metadata in video buffers
mIsMetaDataStoredInVideoBuffers = false;
@@ -566,7 +566,8 @@
if (mCameraFlags & FLAGS_HOT_CAMERA) {
mCamera->unlock();
mCamera.clear();
- CHECK_EQ(OK, mCameraRecordingProxy->startRecording(new ProxyListener(this)));
+ CHECK_EQ((status_t)OK,
+ mCameraRecordingProxy->startRecording(new ProxyListener(this)));
} else {
mCamera->setListener(new CameraSourceListener(this));
mCamera->startRecording();
@@ -718,7 +719,7 @@
return;
}
}
- CHECK_EQ(0, "signalBufferReturned: bogus buffer");
+ CHECK(!"signalBufferReturned: bogus buffer");
}
status_t CameraSource::read(
diff --git a/media/libstagefright/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp
index 83d67b9..26ce7ae 100644
--- a/media/libstagefright/CameraSourceTimeLapse.cpp
+++ b/media/libstagefright/CameraSourceTimeLapse.cpp
@@ -20,9 +20,9 @@
#include <binder/IPCThreadState.h>
#include <binder/MemoryBase.h>
#include <binder/MemoryHeapBase.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/CameraSource.h>
#include <media/stagefright/CameraSourceTimeLapse.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MetaData.h>
#include <camera/Camera.h>
#include <camera/CameraParameters.h>
diff --git a/media/libstagefright/DRMExtractor.cpp b/media/libstagefright/DRMExtractor.cpp
index afc4a80..524c3aa 100644
--- a/media/libstagefright/DRMExtractor.cpp
+++ b/media/libstagefright/DRMExtractor.cpp
@@ -23,6 +23,7 @@
#include <arpa/inet.h>
#include <utils/String8.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/Utils.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaSource.h>
@@ -30,7 +31,6 @@
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDebug.h>
#include <drm/drm_framework_common.h>
#include <utils/Errors.h>
diff --git a/media/libstagefright/FileSource.cpp b/media/libstagefright/FileSource.cpp
index 01f53e4..73c8d03 100644
--- a/media/libstagefright/FileSource.cpp
+++ b/media/libstagefright/FileSource.cpp
@@ -14,8 +14,8 @@
* limitations under the License.
*/
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/FileSource.h>
-#include <media/stagefright/MediaDebug.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
diff --git a/media/libstagefright/JPEGSource.cpp b/media/libstagefright/JPEGSource.cpp
index e818115..bafa4b2 100644
--- a/media/libstagefright/JPEGSource.cpp
+++ b/media/libstagefright/JPEGSource.cpp
@@ -18,10 +18,10 @@
#define LOG_TAG "JPEGSource"
#include <utils/Log.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/JPEGSource.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
@@ -59,7 +59,7 @@
mWidth(0),
mHeight(0),
mOffset(0) {
- CHECK_EQ(parseJPEG(), OK);
+ CHECK_EQ(parseJPEG(), (status_t)OK);
CHECK(mSource->getSize(&mSize) == OK);
}
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 068660b..7ebbe1d 100755
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -23,10 +23,10 @@
#include <pthread.h>
#include <sys/prctl.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MPEG4Writer.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MetaData.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaSource.h>
@@ -70,6 +70,10 @@
status_t dump(int fd, const Vector<String16>& args) const;
private:
+ enum {
+ kMaxCttsOffsetTimeUs = 1000000LL, // 1 second
+ };
+
MPEG4Writer *mOwner;
sp<MetaData> mMeta;
sp<MediaSource> mSource;
@@ -137,11 +141,12 @@
: sampleCount(count), sampleDuration(timescaledDur) {}
uint32_t sampleCount;
- int32_t sampleDuration; // time scale based
+ uint32_t sampleDuration; // time scale based
};
- bool mHasNegativeCttsDeltaDuration;
size_t mNumCttsTableEntries;
List<CttsTableEntry> mCttsTableEntries;
+ int64_t mMinCttsOffsetTimeUs;
+ int64_t mMaxCttsOffsetTimeUs;
// Sequence parameter set or picture parameter set
struct AVCParamSet {
@@ -172,6 +177,8 @@
// Update the audio track's drift information.
void updateDriftTime(const sp<MetaData>& meta);
+ int32_t getStartTimeOffsetScaledTime() const;
+
static void *ThreadWrapper(void *me);
status_t threadEntry();
@@ -471,7 +478,7 @@
!param->findInt32(kKeyTimeScale, &mTimeScale)) {
mTimeScale = 1000;
}
- CHECK(mTimeScale > 0);
+ CHECK_GT(mTimeScale, 0);
ALOGV("movie time scale: %d", mTimeScale);
mStreamableFile = true;
@@ -490,7 +497,7 @@
}
mEstimatedMoovBoxSize = estimateMoovBoxSize(bitRate);
}
- CHECK(mEstimatedMoovBoxSize >= 8);
+ CHECK_GE(mEstimatedMoovBoxSize, 8);
lseek64(mFd, mFreeBoxOffset, SEEK_SET);
writeInt32(mEstimatedMoovBoxSize);
write("free", 4);
@@ -684,7 +691,7 @@
mWriteMoovBoxToMemory = false;
if (mStreamableFile) {
- CHECK(mMoovBoxBufferOffset + 8 <= mEstimatedMoovBoxSize);
+ CHECK_LE(mMoovBoxBufferOffset + 8, mEstimatedMoovBoxSize);
// Moov box
lseek64(mFd, mFreeBoxOffset, SEEK_SET);
@@ -856,7 +863,7 @@
mOffset += length + 4;
} else {
- CHECK(length < 65536);
+ CHECK_LT(length, 65536);
uint8_t x = length >> 8;
::write(mFd, &x, 1);
@@ -1085,7 +1092,7 @@
void MPEG4Writer::setStartTimestampUs(int64_t timeUs) {
ALOGI("setStartTimestampUs: %lld", timeUs);
- CHECK(timeUs >= 0);
+ CHECK_GE(timeUs, 0ll);
Mutex::Autolock autoLock(mLock);
if (mStartTimestampUs < 0 || mStartTimestampUs > timeUs) {
mStartTimestampUs = timeUs;
@@ -1186,9 +1193,6 @@
if (mIsAudio) {
return;
}
- if (duration < 0 && !mHasNegativeCttsDeltaDuration) {
- mHasNegativeCttsDeltaDuration = true;
- }
CttsTableEntry cttsEntry(sampleCount, duration);
mCttsTableEntries.push_back(cttsEntry);
++mNumCttsTableEntries;
@@ -1218,7 +1222,7 @@
mTimeScale = timeScale;
}
- CHECK(mTimeScale > 0);
+ CHECK_GT(mTimeScale, 0);
}
void MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() {
@@ -1299,7 +1303,7 @@
}
}
- CHECK("Received a chunk for a unknown track" == 0);
+ CHECK(!"Received a chunk for a unknown track");
}
void MPEG4Writer::writeChunkToFile(Chunk* chunk) {
@@ -1509,7 +1513,6 @@
mMdatSizeBytes = 0;
mMaxChunkDurationUs = 0;
- mHasNegativeCttsDeltaDuration = false;
pthread_create(&mThread, &attr, ThreadWrapper, this);
pthread_attr_destroy(&attr);
@@ -1833,29 +1836,18 @@
int32_t nChunks = 0;
int32_t nZeroLengthFrames = 0;
int64_t lastTimestampUs = 0; // Previous sample time stamp
- int64_t lastCttsTimeUs = 0; // Previous sample time stamp
int64_t lastDurationUs = 0; // Between the previous two samples
int64_t currDurationTicks = 0; // Timescale based ticks
int64_t lastDurationTicks = 0; // Timescale based ticks
int32_t sampleCount = 1; // Sample count in the current stts table entry
- int64_t currCttsDurTicks = 0; // Timescale based ticks
- int64_t lastCttsDurTicks = 0; // Timescale based ticks
- int32_t cttsSampleCount = 1; // Sample count in the current ctts table entry
- uint32_t previousSampleSize = 0; // Size of the previous sample
+ uint32_t previousSampleSize = 0; // Size of the previous sample
int64_t previousPausedDurationUs = 0;
int64_t timestampUs = 0;
- int64_t cttsDeltaTimeUs = 0;
- bool hasBFrames = false;
+ int64_t cttsOffsetTimeUs = 0;
+ int64_t currCttsOffsetTimeTicks = 0; // Timescale based ticks
+ int64_t lastCttsOffsetTimeTicks = -1; // Timescale based ticks
+ int32_t cttsSampleCount = 0; // Sample count in the current ctts table entry
-#if 1
- // XXX: Samsung's video encoder's output buffer timestamp
- // is not correct. see bug 4724339
- char value[PROPERTY_VALUE_MAX];
- if (property_get("rw.media.record.hasb", value, NULL) &&
- (!strcasecmp(value, "true") || !strcasecmp(value, "1"))) {
- hasBFrames = true;
- }
-#endif
if (mIsAudio) {
prctl(PR_SET_NAME, (unsigned long)"AudioTrackEncoding", 0, 0, 0);
} else {
@@ -1897,7 +1889,7 @@
(const uint8_t *)buffer->data()
+ buffer->range_offset(),
buffer->range_length());
- CHECK_EQ(OK, err);
+ CHECK_EQ((status_t)OK, err);
} else if (mIsMPEG4) {
mCodecSpecificDataSize = buffer->range_length();
mCodecSpecificData = malloc(mCodecSpecificDataSize);
@@ -1963,32 +1955,64 @@
if (mResumed) {
int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs;
- CHECK(durExcludingEarlierPausesUs >= 0);
+ CHECK_GE(durExcludingEarlierPausesUs, 0ll);
int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs;
- CHECK(pausedDurationUs >= lastDurationUs);
+ CHECK_GE(pausedDurationUs, lastDurationUs);
previousPausedDurationUs += pausedDurationUs - lastDurationUs;
mResumed = false;
}
timestampUs -= previousPausedDurationUs;
- CHECK(timestampUs >= 0);
- if (!mIsAudio && hasBFrames) {
+ CHECK_GE(timestampUs, 0ll);
+ if (!mIsAudio) {
/*
* Composition time: timestampUs
* Decoding time: decodingTimeUs
- * Composition time delta = composition time - decoding time
- *
- * We save picture decoding time stamp delta in stts table entries,
- * and composition time delta duration in ctts table entries.
+ * Composition time offset = composition time - decoding time
*/
int64_t decodingTimeUs;
CHECK(meta_data->findInt64(kKeyDecodingTime, &decodingTimeUs));
decodingTimeUs -= previousPausedDurationUs;
- int64_t timeUs = decodingTimeUs;
- cttsDeltaTimeUs = timestampUs - decodingTimeUs;
+ cttsOffsetTimeUs =
+ timestampUs + kMaxCttsOffsetTimeUs - decodingTimeUs;
+ CHECK_GE(cttsOffsetTimeUs, 0ll);
timestampUs = decodingTimeUs;
- ALOGV("decoding time: %lld and ctts delta time: %lld",
- timestampUs, cttsDeltaTimeUs);
+ ALOGV("decoding time: %lld and ctts offset time: %lld",
+ timestampUs, cttsOffsetTimeUs);
+
+ // Update ctts box table if necessary
+ currCttsOffsetTimeTicks =
+ (cttsOffsetTimeUs * mTimeScale + 500000LL) / 1000000LL;
+ CHECK_LE(currCttsOffsetTimeTicks, 0x0FFFFFFFFLL);
+ if (mNumSamples == 0) {
+ // Force the first ctts table entry to have one single entry
+ // so that we can do adjustment for the initial track start
+ // time offset easily in writeCttsBox().
+ lastCttsOffsetTimeTicks = currCttsOffsetTimeTicks;
+ addOneCttsTableEntry(1, currCttsOffsetTimeTicks);
+ cttsSampleCount = 0; // No sample in ctts box is pending
+ } else {
+ if (currCttsOffsetTimeTicks != lastCttsOffsetTimeTicks) {
+ addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks);
+ lastCttsOffsetTimeTicks = currCttsOffsetTimeTicks;
+ cttsSampleCount = 1; // One sample in ctts box is pending
+ } else {
+ ++cttsSampleCount;
+ }
+ }
+
+ // Update ctts time offset range
+ if (mNumSamples == 0) {
+ mMinCttsOffsetTimeUs = currCttsOffsetTimeTicks;
+ mMaxCttsOffsetTimeUs = currCttsOffsetTimeTicks;
+ } else {
+ if (currCttsOffsetTimeTicks > mMaxCttsOffsetTimeUs) {
+ mMaxCttsOffsetTimeUs = currCttsOffsetTimeTicks;
+ } else if (currCttsOffsetTimeTicks < mMinCttsOffsetTimeUs) {
+ mMinCttsOffsetTimeUs = currCttsOffsetTimeTicks;
+ }
+ }
+
}
if (mIsRealTimeRecording) {
@@ -1997,7 +2021,7 @@
}
}
- CHECK(timestampUs >= 0);
+ CHECK_GE(timestampUs, 0ll);
ALOGV("%s media time stamp: %lld and previous paused duration %lld",
mIsAudio? "Audio": "Video", timestampUs, previousPausedDurationUs);
if (timestampUs > mTrackDurationUs) {
@@ -2012,6 +2036,7 @@
currDurationTicks =
((timestampUs * mTimeScale + 500000LL) / 1000000LL -
(lastTimestampUs * mTimeScale + 500000LL) / 1000000LL);
+ CHECK_GE(currDurationTicks, 0ll);
mSampleSizes.push_back(sampleSize);
++mNumSamples;
@@ -2020,25 +2045,12 @@
// Force the first sample to have its own stts entry so that
// we can adjust its value later to maintain the A/V sync.
if (mNumSamples == 3 || currDurationTicks != lastDurationTicks) {
- ALOGV("%s lastDurationUs: %lld us, currDurationTicks: %lld us",
- mIsAudio? "Audio": "Video", lastDurationUs, currDurationTicks);
addOneSttsTableEntry(sampleCount, lastDurationTicks);
sampleCount = 1;
} else {
++sampleCount;
}
- if (!mIsAudio) {
- currCttsDurTicks =
- ((cttsDeltaTimeUs * mTimeScale + 500000LL) / 1000000LL -
- (lastCttsTimeUs * mTimeScale + 500000LL) / 1000000LL);
- if (currCttsDurTicks != lastCttsDurTicks) {
- addOneCttsTableEntry(cttsSampleCount, lastCttsDurTicks);
- cttsSampleCount = 1;
- } else {
- ++cttsSampleCount;
- }
- }
}
if (mSamplesHaveSameSize) {
if (mNumSamples >= 2 && previousSampleSize != sampleSize) {
@@ -2052,11 +2064,6 @@
lastDurationTicks = currDurationTicks;
lastTimestampUs = timestampUs;
- if (!mIsAudio) {
- lastCttsDurTicks = currCttsDurTicks;
- lastCttsTimeUs = cttsDeltaTimeUs;
- }
-
if (isSync != 0) {
addOneStssTableEntry(mNumSamples);
}
@@ -2125,10 +2132,8 @@
if (mNumSamples == 1) {
lastDurationUs = 0; // A single sample's duration
lastDurationTicks = 0;
- lastCttsDurTicks = 0;
} else {
++sampleCount; // Count for the last sample
- ++cttsSampleCount;
}
if (mNumSamples <= 2) {
@@ -2140,7 +2145,14 @@
addOneSttsTableEntry(sampleCount, lastDurationTicks);
}
- addOneCttsTableEntry(cttsSampleCount, lastCttsDurTicks);
+ // The last ctts box may not have been written yet, and this
+ // is to make sure that we write out the last ctts box.
+ if (currCttsOffsetTimeTicks == lastCttsOffsetTimeTicks) {
+ if (cttsSampleCount > 0) {
+ addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks);
+ }
+ }
+
mTrackDurationUs += lastDurationUs;
mReachedEOS = true;
@@ -2406,7 +2418,7 @@
mOwner->writeInt16(0x18); // depth
mOwner->writeInt16(-1); // predefined
- CHECK(23 + mCodecSpecificDataSize < 128);
+ CHECK_LT(23 + mCodecSpecificDataSize, 128);
if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
writeMp4vEsdsBox();
@@ -2465,10 +2477,10 @@
void MPEG4Writer::Track::writeMp4aEsdsBox() {
mOwner->beginBox("esds");
CHECK(mCodecSpecificData);
- CHECK(mCodecSpecificDataSize > 0);
+ CHECK_GT(mCodecSpecificDataSize, 0);
// Make sure all sizes encode to a single byte.
- CHECK(mCodecSpecificDataSize + 23 < 128);
+ CHECK_LT(mCodecSpecificDataSize + 23, 128);
mOwner->writeInt32(0); // version=0, flags=0
mOwner->writeInt8(0x03); // ES_DescrTag
@@ -2502,7 +2514,7 @@
void MPEG4Writer::Track::writeMp4vEsdsBox() {
CHECK(mCodecSpecificData);
- CHECK(mCodecSpecificDataSize > 0);
+ CHECK_GT(mCodecSpecificDataSize, 0);
mOwner->beginBox("esds");
mOwner->writeInt32(0); // version=0, flags=0
@@ -2662,7 +2674,7 @@
void MPEG4Writer::Track::writeAvccBox() {
CHECK(mCodecSpecificData);
- CHECK(mCodecSpecificDataSize >= 5);
+ CHECK_GE(mCodecSpecificDataSize, 5);
// Patch avcc's lengthSize field to match the number
// of bytes we use to indicate the size of a nal unit.
@@ -2690,23 +2702,26 @@
mOwner->endBox(); // pasp
}
+int32_t MPEG4Writer::Track::getStartTimeOffsetScaledTime() const {
+ int64_t trackStartTimeOffsetUs = 0;
+ int64_t moovStartTimeUs = mOwner->getStartTimestampUs();
+ if (mStartTimestampUs != moovStartTimeUs) {
+ CHECK_GT(mStartTimestampUs, moovStartTimeUs);
+ trackStartTimeOffsetUs = mStartTimestampUs - moovStartTimeUs;
+ }
+ return (trackStartTimeOffsetUs * mTimeScale + 500000LL) / 1000000LL;
+}
+
void MPEG4Writer::Track::writeSttsBox() {
mOwner->beginBox("stts");
mOwner->writeInt32(0); // version=0, flags=0
mOwner->writeInt32(mNumSttsTableEntries);
// Compensate for small start time difference from different media tracks
- int64_t trackStartTimeOffsetUs = 0;
- int64_t moovStartTimeUs = mOwner->getStartTimestampUs();
- if (mStartTimestampUs != moovStartTimeUs) {
- CHECK(mStartTimestampUs > moovStartTimeUs);
- trackStartTimeOffsetUs = mStartTimestampUs - moovStartTimeUs;
- }
List<SttsTableEntry>::iterator it = mSttsTableEntries.begin();
CHECK(it != mSttsTableEntries.end() && it->sampleCount == 1);
mOwner->writeInt32(it->sampleCount);
- int32_t dur = (trackStartTimeOffsetUs * mTimeScale + 500000LL) / 1000000LL;
- mOwner->writeInt32(dur + it->sampleDuration);
+ mOwner->writeInt32(getStartTimeOffsetScaledTime() + it->sampleDuration);
int64_t totalCount = 1;
while (++it != mSttsTableEntries.end()) {
@@ -2714,7 +2729,7 @@
mOwner->writeInt32(it->sampleDuration);
totalCount += it->sampleCount;
}
- CHECK(totalCount == mNumSamples);
+ CHECK_EQ(totalCount, mNumSamples);
mOwner->endBox(); // stts
}
@@ -2723,6 +2738,11 @@
return;
}
+ // There is no B frame at all
+ if (mMinCttsOffsetTimeUs == mMaxCttsOffsetTimeUs) {
+ return;
+ }
+
// Do not write ctts box when there is no need to have it.
if ((mNumCttsTableEntries == 1 &&
mCttsTableEntries.begin()->sampleDuration == 0) ||
@@ -2730,24 +2750,29 @@
return;
}
- ALOGV("ctts box has %d entries", mNumCttsTableEntries);
+ ALOGD("ctts box has %d entries with range [%lld, %lld]",
+ mNumCttsTableEntries, mMinCttsOffsetTimeUs, mMaxCttsOffsetTimeUs);
mOwner->beginBox("ctts");
- if (mHasNegativeCttsDeltaDuration) {
- mOwner->writeInt32(0x00010000); // version=1, flags=0
- } else {
- mOwner->writeInt32(0); // version=0, flags=0
- }
+ // Version 1 allows to use negative offset time value, but
+ // we are sticking to version 0 for now.
+ mOwner->writeInt32(0); // version=0, flags=0
mOwner->writeInt32(mNumCttsTableEntries);
- int64_t totalCount = 0;
- for (List<CttsTableEntry>::iterator it = mCttsTableEntries.begin();
- it != mCttsTableEntries.end(); ++it) {
+ // Compensate for small start time difference from different media tracks
+ List<CttsTableEntry>::iterator it = mCttsTableEntries.begin();
+ CHECK(it != mCttsTableEntries.end() && it->sampleCount == 1);
+ mOwner->writeInt32(it->sampleCount);
+ mOwner->writeInt32(getStartTimeOffsetScaledTime() +
+ it->sampleDuration - mMinCttsOffsetTimeUs);
+
+ int64_t totalCount = 1;
+ while (++it != mCttsTableEntries.end()) {
mOwner->writeInt32(it->sampleCount);
- mOwner->writeInt32(it->sampleDuration);
+ mOwner->writeInt32(it->sampleDuration - mMinCttsOffsetTimeUs);
totalCount += it->sampleCount;
}
- CHECK(totalCount == mNumSamples);
+ CHECK_EQ(totalCount, mNumSamples);
mOwner->endBox(); // ctts
}
diff --git a/media/libstagefright/MediaBuffer.cpp b/media/libstagefright/MediaBuffer.cpp
index 96271e4..11b80bf 100644
--- a/media/libstagefright/MediaBuffer.cpp
+++ b/media/libstagefright/MediaBuffer.cpp
@@ -22,8 +22,8 @@
#include <stdlib.h>
#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MetaData.h>
#include <ui/GraphicBuffer.h>
@@ -157,7 +157,7 @@
}
MediaBuffer::~MediaBuffer() {
- CHECK_EQ(mObserver, NULL);
+ CHECK(mObserver == NULL);
if (mOwnsData && mData != NULL) {
free(mData);
@@ -188,7 +188,7 @@
}
MediaBuffer *MediaBuffer::clone() {
- CHECK_EQ(mGraphicBuffer, NULL);
+ CHECK(mGraphicBuffer == NULL);
MediaBuffer *buffer = new MediaBuffer(mData, mSize);
buffer->set_range(mRangeOffset, mRangeLength);
diff --git a/media/libstagefright/MediaBufferGroup.cpp b/media/libstagefright/MediaBufferGroup.cpp
index c8d05f4..80aae51 100644
--- a/media/libstagefright/MediaBufferGroup.cpp
+++ b/media/libstagefright/MediaBufferGroup.cpp
@@ -17,9 +17,9 @@
#define LOG_TAG "MediaBufferGroup"
#include <utils/Log.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
namespace android {
diff --git a/media/libstagefright/MediaSourceSplitter.cpp b/media/libstagefright/MediaSourceSplitter.cpp
index 8af0694..3b64ded 100644
--- a/media/libstagefright/MediaSourceSplitter.cpp
+++ b/media/libstagefright/MediaSourceSplitter.cpp
@@ -18,8 +18,8 @@
#define LOG_TAG "MediaSourceSplitter"
#include <utils/Log.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaSourceSplitter.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MetaData.h>
diff --git a/media/libstagefright/MetaData.cpp b/media/libstagefright/MetaData.cpp
index 884f3b4..66dec90 100644
--- a/media/libstagefright/MetaData.cpp
+++ b/media/libstagefright/MetaData.cpp
@@ -17,7 +17,7 @@
#include <stdlib.h>
#include <string.h>
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MetaData.h>
namespace android {
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 381320b..470f750 100755
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -2187,7 +2187,7 @@
}
}
-int64_t OMXCodec::retrieveDecodingTimeUs(bool isCodecSpecific) {
+int64_t OMXCodec::getDecodingTimeUs() {
CHECK(mIsEncoder && mIsVideo);
if (mDecodingTimeList.empty()) {
@@ -2199,12 +2199,7 @@
List<int64_t>::iterator it = mDecodingTimeList.begin();
int64_t timeUs = *it;
-
- // If the output buffer is codec specific configuration,
- // do not remove the decoding time from the list.
- if (!isCodecSpecific) {
- mDecodingTimeList.erase(it);
- }
+ mDecodingTimeList.erase(it);
return timeUs;
}
@@ -2384,7 +2379,7 @@
}
if (mIsEncoder && mIsVideo) {
- int64_t decodingTimeUs = retrieveDecodingTimeUs(isCodecSpecific);
+ int64_t decodingTimeUs = isCodecSpecific? 0: getDecodingTimeUs();
buffer->meta_data()->setInt64(kKeyDecodingTime, decodingTimeUs);
}
diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp
index 73efc27..5e79e78 100644
--- a/media/libstagefright/OggExtractor.cpp
+++ b/media/libstagefright/OggExtractor.cpp
@@ -21,10 +21,10 @@
#include "include/OggExtractor.h"
#include <cutils/properties.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaSource.h>
diff --git a/media/libstagefright/SampleIterator.cpp b/media/libstagefright/SampleIterator.cpp
index 81ec5c1..eae721b 100644
--- a/media/libstagefright/SampleIterator.cpp
+++ b/media/libstagefright/SampleIterator.cpp
@@ -22,8 +22,8 @@
#include <arpa/inet.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/Utils.h>
#include "include/SampleTable.h"
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index 43bfd9e..35f9c1f 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -20,10 +20,10 @@
#include "include/StagefrightMetadataRetriever.h"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/ColorConverter.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/FileSource.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/OMXCodec.h>
@@ -37,7 +37,7 @@
ALOGV("StagefrightMetadataRetriever()");
DataSource::RegisterDefaultSniffers();
- CHECK_EQ(mClient.connect(), OK);
+ CHECK_EQ(mClient.connect(), (status_t)OK);
}
StagefrightMetadataRetriever::~StagefrightMetadataRetriever() {
@@ -169,7 +169,7 @@
|| (buffer != NULL && buffer->range_length() == 0));
if (err != OK) {
- CHECK_EQ(buffer, NULL);
+ CHECK(buffer == NULL);
ALOGV("decoding frame failed.");
decoder->stop();
diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
index d068381..aa047d6 100644
--- a/media/libstagefright/SurfaceMediaSource.cpp
+++ b/media/libstagefright/SurfaceMediaSource.cpp
@@ -16,14 +16,14 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "SurfaceMediaSource"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/SurfaceMediaSource.h>
-#include <ui/GraphicBuffer.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/openmax/OMX_IVCommon.h>
#include <media/stagefright/MetadataBufferType.h>
+#include <ui/GraphicBuffer.h>
#include <surfaceflinger/ISurfaceComposer.h>
#include <surfaceflinger/SurfaceComposerClient.h>
#include <surfaceflinger/IGraphicBufferAlloc.h>
@@ -855,7 +855,7 @@
}
if (!foundBuffer) {
- CHECK_EQ(0, "signalBufferReturned: bogus buffer");
+ CHECK(!"signalBufferReturned: bogus buffer");
}
}
diff --git a/media/libstagefright/ThrottledSource.cpp b/media/libstagefright/ThrottledSource.cpp
index 88e07b0..b1fcafd 100644
--- a/media/libstagefright/ThrottledSource.cpp
+++ b/media/libstagefright/ThrottledSource.cpp
@@ -16,7 +16,7 @@
#include "include/ThrottledSource.h"
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
namespace android {
diff --git a/media/libstagefright/TimedEventQueue.cpp b/media/libstagefright/TimedEventQueue.cpp
index 12c9c36..f4b5d4f 100644
--- a/media/libstagefright/TimedEventQueue.cpp
+++ b/media/libstagefright/TimedEventQueue.cpp
@@ -31,7 +31,7 @@
#include <sys/prctl.h>
#include <sys/time.h>
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
#ifdef ANDROID_SIMULATOR
#include <jni.h>
diff --git a/media/libstagefright/VideoSourceDownSampler.cpp b/media/libstagefright/VideoSourceDownSampler.cpp
index 1b669904..90a42c9 100644
--- a/media/libstagefright/VideoSourceDownSampler.cpp
+++ b/media/libstagefright/VideoSourceDownSampler.cpp
@@ -17,9 +17,9 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "VideoSourceDownSampler"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/VideoSourceDownSampler.h>
#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/YUVImage.h>
#include <media/stagefright/YUVCanvas.h>
diff --git a/media/libstagefright/WAVExtractor.cpp b/media/libstagefright/WAVExtractor.cpp
index 0bcaf08..501f4806 100644
--- a/media/libstagefright/WAVExtractor.cpp
+++ b/media/libstagefright/WAVExtractor.cpp
@@ -20,9 +20,9 @@
#include "include/WAVExtractor.h"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaSource.h>
@@ -217,7 +217,7 @@
kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_G711_ALAW);
break;
default:
- CHECK_EQ(mWaveFormat, WAVE_FORMAT_MULAW);
+ CHECK_EQ(mWaveFormat, (uint16_t)WAVE_FORMAT_MULAW);
mTrackMeta->setCString(
kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_G711_MLAW);
break;
@@ -362,7 +362,7 @@
// Convert 8-bit unsigned samples to 16-bit signed.
MediaBuffer *tmp;
- CHECK_EQ(mGroup->acquire_buffer(&tmp), OK);
+ CHECK_EQ(mGroup->acquire_buffer(&tmp), (status_t)OK);
// The new buffer holds the sample number of samples, but each
// one is 2 bytes wide.
diff --git a/media/libstagefright/WVMExtractor.cpp b/media/libstagefright/WVMExtractor.cpp
index 1e4e049..c7ad513 100644
--- a/media/libstagefright/WVMExtractor.cpp
+++ b/media/libstagefright/WVMExtractor.cpp
@@ -21,6 +21,7 @@
#include <arpa/inet.h>
#include <utils/String8.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/Utils.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaSource.h>
@@ -28,7 +29,6 @@
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDebug.h>
#include <dlfcn.h>
#include <utils/Errors.h>
diff --git a/media/libstagefright/codecs/aacenc/AACEncoder.cpp b/media/libstagefright/codecs/aacenc/AACEncoder.cpp
index 2b8633d..8b5007e 100644
--- a/media/libstagefright/codecs/aacenc/AACEncoder.cpp
+++ b/media/libstagefright/codecs/aacenc/AACEncoder.cpp
@@ -22,8 +22,8 @@
#include "voAAC.h"
#include "cmnMemory.h"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
@@ -114,8 +114,8 @@
ALOGV("setAudioSpecificConfigData: %d hz, %d bps, and %d channels",
mSampleRate, mBitRate, mChannels);
- int32_t index;
- CHECK_EQ(OK, getSampleRateTableIndex(mSampleRate, index));
+ int32_t index = 0;
+ CHECK_EQ((status_t)OK, getSampleRateTableIndex(mSampleRate, index));
if (mChannels > 2 || mChannels <= 0) {
ALOGE("Unsupported number of channels(%d)", mChannels);
return UNKNOWN_ERROR;
@@ -142,7 +142,7 @@
mBufferGroup = new MediaBufferGroup;
mBufferGroup->add_buffer(new MediaBuffer(2048));
- CHECK_EQ(OK, initCheck());
+ CHECK_EQ((status_t)OK, initCheck());
mNumInputSamples = 0;
mAnchorTimeUs = 0;
@@ -183,7 +183,7 @@
mSource->stop();
if (mEncoderHandle) {
- CHECK_EQ(VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle));
+ CHECK_EQ((VO_U32)VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle));
mEncoderHandle = NULL;
}
delete mApiHandle;
@@ -223,7 +223,7 @@
CHECK(options == NULL || !options->getSeekTo(&seekTimeUs, &mode));
MediaBuffer *buffer;
- CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), OK);
+ CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), (status_t)OK);
uint8_t *outPtr = (uint8_t *)buffer->data();
bool readFromSource = false;
int64_t wallClockTimeUs = -1;
@@ -255,7 +255,7 @@
}
size_t align = mInputBuffer->range_length() % sizeof(int16_t);
- CHECK_EQ(align, 0);
+ CHECK_EQ(align, (size_t)0);
int64_t timeUs;
if (mInputBuffer->meta_data()->findInt64(kKeyDriftTime, &timeUs)) {
diff --git a/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp b/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp
index 3afbc4f..27d7e4d 100644
--- a/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp
+++ b/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp
@@ -18,8 +18,8 @@
#include "gsmamr_enc.h"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
@@ -210,7 +210,7 @@
}
MediaBuffer *buffer;
- CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), OK);
+ CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), (status_t)OK);
uint8_t *outPtr = (uint8_t *)buffer->data();
diff --git a/media/libstagefright/codecs/amrwbenc/AMRWBEncoder.cpp b/media/libstagefright/codecs/amrwbenc/AMRWBEncoder.cpp
index 60b1163..7fd3a95 100644
--- a/media/libstagefright/codecs/amrwbenc/AMRWBEncoder.cpp
+++ b/media/libstagefright/codecs/amrwbenc/AMRWBEncoder.cpp
@@ -22,8 +22,8 @@
#include "voAMRWB.h"
#include "cmnMemory.h"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
@@ -134,7 +134,7 @@
// The largest buffer size is header + 477 bits
mBufferGroup->add_buffer(new MediaBuffer(1024));
- CHECK_EQ(OK, initCheck());
+ CHECK_EQ((status_t)OK, initCheck());
mNumFramesOutput = 0;
@@ -163,7 +163,7 @@
mBufferGroup = NULL;
- CHECK_EQ(VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle));
+ CHECK_EQ((VO_U32)VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle));
mEncoderHandle = NULL;
delete mApiHandle;
@@ -222,7 +222,7 @@
}
size_t align = mInputBuffer->range_length() % sizeof(int16_t);
- CHECK_EQ(align, 0);
+ CHECK_EQ(align, (size_t)0);
int64_t timeUs;
if (mInputBuffer->meta_data()->findInt64(kKeyDriftTime, &timeUs)) {
@@ -271,7 +271,7 @@
CHECK(VO_ERR_NONE == mApiHandle->SetInputData(mEncoderHandle,&inputData));
MediaBuffer *buffer;
- CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), OK);
+ CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), (status_t)OK);
uint8_t *outPtr = (uint8_t *)buffer->data();
VO_CODECBUFFER outputData;
diff --git a/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp b/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp
index e202a2b..7533f07 100644
--- a/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp
+++ b/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp
@@ -24,8 +24,8 @@
#include "avcenc_int.h"
#include "OMX_Video.h"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
@@ -417,7 +417,7 @@
*out = NULL;
MediaBuffer *outputBuffer;
- CHECK_EQ(OK, mGroup->acquire_buffer(&outputBuffer));
+ CHECK_EQ((status_t)OK, mGroup->acquire_buffer(&outputBuffer));
uint8_t *outPtr = (uint8_t *) outputBuffer->data();
uint32_t dataLength = outputBuffer->size();
@@ -557,9 +557,9 @@
encoderStatus = PVAVCEncodeNAL(mHandle, outPtr, &dataLength, &type);
if (encoderStatus == AVCENC_SUCCESS) {
outputBuffer->meta_data()->setInt32(kKeyIsSyncFrame, mIsIDRFrame);
- CHECK_EQ(NULL, PVAVCEncGetOverrunBuffer(mHandle));
+ CHECK(NULL == PVAVCEncGetOverrunBuffer(mHandle));
} else if (encoderStatus == AVCENC_PICTURE_READY) {
- CHECK_EQ(NULL, PVAVCEncGetOverrunBuffer(mHandle));
+ CHECK(NULL == PVAVCEncGetOverrunBuffer(mHandle));
if (mIsIDRFrame) {
outputBuffer->meta_data()->setInt32(kKeyIsSyncFrame, mIsIDRFrame);
mIsIDRFrame = 0;
diff --git a/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp b/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp
index d538603..20b0f8d 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp
+++ b/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp
@@ -23,8 +23,8 @@
#include "mp4enc_api.h"
#include "OMX_Video.h"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
@@ -379,7 +379,7 @@
*out = NULL;
MediaBuffer *outputBuffer;
- CHECK_EQ(OK, mGroup->acquire_buffer(&outputBuffer));
+ CHECK_EQ((status_t)OK, mGroup->acquire_buffer(&outputBuffer));
uint8_t *outPtr = (uint8_t *) outputBuffer->data();
int32_t dataLength = outputBuffer->size();
@@ -467,7 +467,7 @@
mInputBuffer = NULL;
return UNKNOWN_ERROR;
}
- CHECK_EQ(NULL, PVGetOverrunBuffer(mHandle));
+ CHECK(NULL == PVGetOverrunBuffer(mHandle));
if (hintTrack.CodeType == 0) { // I-frame serves as sync frame
outputBuffer->meta_data()->setInt32(kKeyIsSyncFrame, 1);
}
diff --git a/media/libstagefright/colorconversion/ColorConverter.cpp b/media/libstagefright/colorconversion/ColorConverter.cpp
index f3ef3de..597167f 100644
--- a/media/libstagefright/colorconversion/ColorConverter.cpp
+++ b/media/libstagefright/colorconversion/ColorConverter.cpp
@@ -18,8 +18,8 @@
#define LOG_TAG "ColorConverter"
#include <utils/Log.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/ColorConverter.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaErrors.h>
namespace android {
diff --git a/media/libstagefright/id3/Android.mk b/media/libstagefright/id3/Android.mk
index 23c8e44..ff35d4a 100644
--- a/media/libstagefright/id3/Android.mk
+++ b/media/libstagefright/id3/Android.mk
@@ -16,7 +16,7 @@
testid3.cpp
LOCAL_SHARED_LIBRARIES := \
- libstagefright libutils libbinder
+ libstagefright libutils libbinder libstagefright_foundation
LOCAL_STATIC_LIBRARIES := \
libstagefright_id3
diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
index 6dde9d8..2e92926 100644
--- a/media/libstagefright/id3/ID3.cpp
+++ b/media/libstagefright/id3/ID3.cpp
@@ -20,8 +20,8 @@
#include "../include/ID3.h"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/Utils.h>
#include <utils/String8.h>
#include <byteswap.h>
diff --git a/media/libstagefright/id3/testid3.cpp b/media/libstagefright/id3/testid3.cpp
index 0741045..bc4572c 100644
--- a/media/libstagefright/id3/testid3.cpp
+++ b/media/libstagefright/id3/testid3.cpp
@@ -23,7 +23,7 @@
#include <binder/ProcessState.h>
#include <media/stagefright/FileSource.h>
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
#define MAXPATHLEN 256
@@ -70,7 +70,7 @@
void scanFile(const char *path) {
sp<FileSource> file = new FileSource(path);
- CHECK_EQ(file->initCheck(), OK);
+ CHECK_EQ(file->initCheck(), (status_t)OK);
ID3 tag(file);
if (!tag.isValid()) {
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index a7a3d47..4c7bfa6 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -258,7 +258,7 @@
void setVideoSource(sp<MediaSource> source);
status_t initVideoDecoder(uint32_t flags = 0);
- void addTextSource(sp<MediaSource> source);
+ void addTextSource(const sp<MediaSource>& source);
void onStreamDone();
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index a1644d2..a0db719 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -93,7 +93,10 @@
void advance();
void reset();
- void seek(int64_t seekTimeUs, bool seekToKeyFrame);
+
+ void seek(
+ int64_t seekTimeUs, bool seekToKeyFrame,
+ int64_t *actualFrameTimeUs);
const mkvparser::Block *block() const;
int64_t blockTimeUs() const;
@@ -303,22 +306,52 @@
} while (!eos() && block()->GetTrackNumber() != mTrackNum);
}
-void BlockIterator::seek(int64_t seekTimeUs, bool seekToKeyFrame) {
+void BlockIterator::seek(
+ int64_t seekTimeUs, bool seekToKeyFrame,
+ int64_t *actualFrameTimeUs) {
Mutex::Autolock autoLock(mExtractor->mLock);
- mCluster = mExtractor->mSegment->FindCluster(seekTimeUs * 1000ll);
+ *actualFrameTimeUs = -1ll;
+
+ int64_t seekTimeNs = seekTimeUs * 1000ll;
+
+ mCluster = mExtractor->mSegment->FindCluster(seekTimeNs);
mBlockEntry = NULL;
mBlockEntryIndex = 0;
- do {
- advance_l();
- }
- while (!eos() && block()->GetTrackNumber() != mTrackNum);
+ long prevKeyFrameBlockEntryIndex = -1;
- if (seekToKeyFrame) {
- while (!eos() && !mBlockEntry->GetBlock()->IsKey()) {
- advance_l();
+ for (;;) {
+ advance_l();
+
+ if (eos()) {
+ break;
}
+
+ if (block()->GetTrackNumber() != mTrackNum) {
+ continue;
+ }
+
+ if (block()->IsKey()) {
+ prevKeyFrameBlockEntryIndex = mBlockEntryIndex - 1;
+ }
+
+ int64_t timeNs = block()->GetTime(mCluster);
+
+ if (timeNs >= seekTimeNs) {
+ *actualFrameTimeUs = (timeNs + 500ll) / 1000ll;
+ break;
+ }
+ }
+
+ if (eos()) {
+ return;
+ }
+
+ if (seekToKeyFrame && !block()->IsKey()) {
+ CHECK_GE(prevKeyFrameBlockEntryIndex, 0);
+ mBlockEntryIndex = prevKeyFrameBlockEntryIndex;
+ advance_l();
}
}
@@ -397,6 +430,8 @@
MediaBuffer **out, const ReadOptions *options) {
*out = NULL;
+ int64_t targetSampleTimeUs = -1ll;
+
int64_t seekTimeUs;
ReadOptions::SeekMode mode;
if (options && options->getSeekTo(&seekTimeUs, &mode)
@@ -406,10 +441,14 @@
// Apparently keyframe indication in audio tracks is unreliable,
// fortunately in all our currently supported audio encodings every
// frame is effectively a keyframe.
- mBlockIter.seek(seekTimeUs, !mIsAudio);
+ int64_t actualFrameTimeUs;
+ mBlockIter.seek(seekTimeUs, !mIsAudio, &actualFrameTimeUs);
+
+ if (mode == ReadOptions::SEEK_CLOSEST) {
+ targetSampleTimeUs = actualFrameTimeUs;
+ }
}
-again:
while (mPendingFrames.empty()) {
status_t err = readBlock();
@@ -424,6 +463,11 @@
mPendingFrames.erase(mPendingFrames.begin());
if (mType != AVC) {
+ if (targetSampleTimeUs >= 0ll) {
+ frame->meta_data()->setInt64(
+ kKeyTargetTime, targetSampleTimeUs);
+ }
+
*out = frame;
return OK;
@@ -506,6 +550,11 @@
frame->release();
frame = NULL;
+ if (targetSampleTimeUs >= 0ll) {
+ buffer->meta_data()->setInt64(
+ kKeyTargetTime, targetSampleTimeUs);
+ }
+
*out = buffer;
return OK;
diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
index 03033f5..e1589b4 100644
--- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
@@ -22,8 +22,8 @@
#include "include/LiveSession.h"
#include "include/NuCachedSource2.h"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaSource.h>
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index ace883c..f11fcd2 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -25,7 +25,7 @@
#include "../include/OMXNodeInstance.h"
#include <binder/IMemory.h>
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <utils/threads.h>
#include "OMXMaster.h"
@@ -102,7 +102,7 @@
if (status != WOULD_BLOCK) {
// Other than join to self, the only other error return codes are
// whatever readyToRun() returns, and we don't override that
- CHECK_EQ(status, NO_ERROR);
+ CHECK_EQ(status, (status_t)NO_ERROR);
}
}
diff --git a/media/libstagefright/omx/OMXComponentBase.cpp b/media/libstagefright/omx/OMXComponentBase.cpp
index 35227a0..7d11dce 100644
--- a/media/libstagefright/omx/OMXComponentBase.cpp
+++ b/media/libstagefright/omx/OMXComponentBase.cpp
@@ -18,7 +18,7 @@
#include <stdlib.h>
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
namespace android {
@@ -33,7 +33,7 @@
OMXComponentBase::~OMXComponentBase() {}
void OMXComponentBase::setComponentHandle(OMX_COMPONENTTYPE *handle) {
- CHECK_EQ(mComponentHandle, NULL);
+ CHECK(mComponentHandle == NULL);
mComponentHandle = handle;
}
diff --git a/media/libstagefright/omx/OMXMaster.cpp b/media/libstagefright/omx/OMXMaster.cpp
index d698939..6b6d0ab 100644
--- a/media/libstagefright/omx/OMXMaster.cpp
+++ b/media/libstagefright/omx/OMXMaster.cpp
@@ -24,7 +24,7 @@
#include <dlfcn.h>
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
namespace android {
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 8938e33..099c4f5 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -24,8 +24,8 @@
#include <OMX_Component.h>
#include <binder/IMemory.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/HardwareAPI.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaErrors.h>
namespace android {
@@ -91,11 +91,11 @@
}
OMXNodeInstance::~OMXNodeInstance() {
- CHECK_EQ(mHandle, NULL);
+ CHECK(mHandle == NULL);
}
void OMXNodeInstance::setHandle(OMX::node_id node_id, OMX_HANDLETYPE handle) {
- CHECK_EQ(mHandle, NULL);
+ CHECK(mHandle == NULL);
mNodeID = node_id;
mHandle = handle;
}
diff --git a/media/libstagefright/omx/tests/Android.mk b/media/libstagefright/omx/tests/Android.mk
index 41c08be..0c0a70c 100644
--- a/media/libstagefright/omx/tests/Android.mk
+++ b/media/libstagefright/omx/tests/Android.mk
@@ -5,7 +5,7 @@
OMXHarness.cpp \
LOCAL_SHARED_LIBRARIES := \
- libstagefright libbinder libmedia libutils
+ libstagefright libbinder libmedia libutils libstagefright_foundation
LOCAL_C_INCLUDES := \
$(JNI_H_INCLUDE) \
diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp
index 8faf544..fab1771 100644
--- a/media/libstagefright/omx/tests/OMXHarness.cpp
+++ b/media/libstagefright/omx/tests/OMXHarness.cpp
@@ -26,9 +26,9 @@
#include <binder/IServiceManager.h>
#include <binder/MemoryDealer.h>
#include <media/IMediaPlayerService.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaExtractor.h>
@@ -155,7 +155,7 @@
if (err == TIMED_OUT) {
return err;
}
- CHECK_EQ(err, OK);
+ CHECK_EQ(err, (status_t)OK);
}
}
@@ -317,7 +317,7 @@
EXPECT_SUCCESS(err, "allocatePortBuffers(input)");
err = dequeueMessageForNode(node, &msg, DEFAULT_TIMEOUT);
- CHECK_EQ(err, TIMED_OUT);
+ CHECK_EQ(err, (status_t)TIMED_OUT);
Vector<Buffer> outputBuffers;
err = allocatePortBuffers(dealer, node, 1, &outputBuffers);
@@ -412,7 +412,7 @@
// Make sure node doesn't just transition to loaded before we are done
// freeing all input and output buffers.
err = dequeueMessageForNode(node, &msg, DEFAULT_TIMEOUT);
- CHECK_EQ(err, TIMED_OUT);
+ CHECK_EQ(err, (status_t)TIMED_OUT);
for (size_t i = 0; i < inputBuffers.size(); ++i) {
err = mOMX->freeBuffer(node, 0, inputBuffers[i].mID);
@@ -420,7 +420,7 @@
}
err = dequeueMessageForNode(node, &msg, DEFAULT_TIMEOUT);
- CHECK_EQ(err, TIMED_OUT);
+ CHECK_EQ(err, (status_t)TIMED_OUT);
for (size_t i = 0; i < outputBuffers.size(); ++i) {
err = mOMX->freeBuffer(node, 1, outputBuffers[i].mID);
@@ -584,7 +584,7 @@
return UNKNOWN_ERROR;
}
- CHECK_EQ(seekSource->start(), OK);
+ CHECK_EQ(seekSource->start(), (status_t)OK);
sp<MediaSource> codec = OMXCodec::Create(
mOMX, source->getFormat(), false /* createEncoder */,
@@ -592,7 +592,7 @@
CHECK(codec != NULL);
- CHECK_EQ(codec->start(), OK);
+ CHECK_EQ(codec->start(), (status_t)OK);
int64_t durationUs;
CHECK(source->getFormat()->findInt64(kKeyDuration, &durationUs));
@@ -638,7 +638,7 @@
requestedSeekTimeUs, MediaSource::ReadOptions::SEEK_NEXT_SYNC);
if (seekSource->read(&buffer, &options) != OK) {
- CHECK_EQ(buffer, NULL);
+ CHECK(buffer == NULL);
actualSeekTimeUs = -1;
} else {
CHECK(buffer != NULL);
@@ -659,7 +659,7 @@
err = codec->read(&buffer, &options);
options.clearSeekTo();
if (err == INFO_FORMAT_CHANGED) {
- CHECK_EQ(buffer, NULL);
+ CHECK(buffer == NULL);
continue;
}
if (err == OK) {
@@ -670,7 +670,7 @@
continue;
}
} else {
- CHECK_EQ(buffer, NULL);
+ CHECK(buffer == NULL);
}
break;
@@ -679,7 +679,7 @@
if (requestedSeekTimeUs < 0) {
// Linear read.
if (err != OK) {
- CHECK_EQ(buffer, NULL);
+ CHECK(buffer == NULL);
} else {
CHECK(buffer != NULL);
buffer->release();
@@ -694,8 +694,8 @@
"We attempted to seek beyond EOS and expected "
"ERROR_END_OF_STREAM to be returned, but instead "
"we found some other error.");
- CHECK_EQ(err, ERROR_END_OF_STREAM);
- CHECK_EQ(buffer, NULL);
+ CHECK_EQ(err, (status_t)ERROR_END_OF_STREAM);
+ CHECK(buffer == NULL);
} else {
EXPECT(err == OK,
"Expected a valid buffer to be returned from "
@@ -715,7 +715,7 @@
buffer->release();
buffer = NULL;
- CHECK_EQ(codec->stop(), OK);
+ CHECK_EQ(codec->stop(), (status_t)OK);
return UNKNOWN_ERROR;
}
@@ -725,7 +725,7 @@
}
}
- CHECK_EQ(codec->stop(), OK);
+ CHECK_EQ(codec->stop(), (status_t)OK);
return OK;
}
@@ -841,7 +841,7 @@
srand(seed);
sp<Harness> h = new Harness;
- CHECK_EQ(h->initCheck(), OK);
+ CHECK_EQ(h->initCheck(), (status_t)OK);
if (argc == 0) {
h->testAll();
diff --git a/media/libstagefright/tests/SurfaceMediaSource_test.cpp b/media/libstagefright/tests/SurfaceMediaSource_test.cpp
index 76b507f..d7cec04 100644
--- a/media/libstagefright/tests/SurfaceMediaSource_test.cpp
+++ b/media/libstagefright/tests/SurfaceMediaSource_test.cpp
@@ -35,7 +35,7 @@
#include <binder/ProcessState.h>
#include <ui/FramebufferNativeWindow.h>
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
@@ -475,7 +475,7 @@
mr->setVideoFrameRate(fps);
mr->prepare();
ALOGV("Starting MediaRecorder...");
- CHECK_EQ(OK, mr->start());
+ CHECK_EQ((status_t)OK, mr->start());
return mr;
}
@@ -757,7 +757,7 @@
ASSERT_EQ(NO_ERROR, native_window_api_disconnect(mANW.get(), NATIVE_WINDOW_API_CPU));
ALOGV("Stopping MediaRecorder...");
- CHECK_EQ(OK, mr->stop());
+ CHECK_EQ((status_t)OK, mr->stop());
mr.clear();
close(fd);
}
@@ -886,7 +886,7 @@
mEglSurface = EGL_NO_SURFACE;
ALOGV("Stopping MediaRecorder...");
- CHECK_EQ(OK, mr->stop());
+ CHECK_EQ((status_t)OK, mr->stop());
mr.clear();
close(fd);
}
@@ -929,7 +929,7 @@
mEglSurface = EGL_NO_SURFACE;
ALOGV("Stopping MediaRecorder...");
- CHECK_EQ(OK, mr->stop());
+ CHECK_EQ((status_t)OK, mr->stop());
mr.clear();
close(fd);
}
diff --git a/media/libstagefright/timedtext/TimedTextInBandSource.cpp b/media/libstagefright/timedtext/TimedTextInBandSource.cpp
index f2c4d54..afb73fb 100644
--- a/media/libstagefright/timedtext/TimedTextInBandSource.cpp
+++ b/media/libstagefright/timedtext/TimedTextInBandSource.cpp
@@ -19,8 +19,8 @@
#include <utils/Log.h>
#include <binder/Parcel.h>
+#include <media/stagefright/foundation/ADebug.h> // CHECK_XX macro
#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDebug.h> // CHECK_XX macro
#include <media/stagefright/MediaDefs.h> // for MEDIA_MIMETYPE_xxx
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaSource.h>
diff --git a/media/libstagefright/timedtext/TimedTextPlayer.cpp b/media/libstagefright/timedtext/TimedTextPlayer.cpp
index 8c2df88..bf7cbf6 100644
--- a/media/libstagefright/timedtext/TimedTextPlayer.cpp
+++ b/media/libstagefright/timedtext/TimedTextPlayer.cpp
@@ -18,8 +18,8 @@
#define LOG_TAG "TimedTextPlayer"
#include <utils/Log.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaErrors.h>
#include <media/MediaPlayerInterface.h>
diff --git a/media/libstagefright/yuv/YUVCanvas.cpp b/media/libstagefright/yuv/YUVCanvas.cpp
index 38aa779..4c9fee81 100644
--- a/media/libstagefright/yuv/YUVCanvas.cpp
+++ b/media/libstagefright/yuv/YUVCanvas.cpp
@@ -17,7 +17,7 @@
#define LOG_NDEBUG 0
#define LOG_TAG "YUVCanvas"
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/YUVCanvas.h>
#include <media/stagefright/YUVImage.h>
#include <ui/Rect.h>
diff --git a/media/libstagefright/yuv/YUVImage.cpp b/media/libstagefright/yuv/YUVImage.cpp
index 0d67c96..7b9000b 100644
--- a/media/libstagefright/yuv/YUVImage.cpp
+++ b/media/libstagefright/yuv/YUVImage.cpp
@@ -17,9 +17,9 @@
#define LOG_NDEBUG 0
#define LOG_TAG "YUVImage"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/YUVImage.h>
#include <ui/Rect.h>
-#include <media/stagefright/MediaDebug.h>
namespace android {
diff --git a/media/tests/omxjpegdecoder/Android.mk b/media/tests/omxjpegdecoder/Android.mk
index 81c6167..025a131 100644
--- a/media/tests/omxjpegdecoder/Android.mk
+++ b/media/tests/omxjpegdecoder/Android.mk
@@ -26,6 +26,7 @@
libcutils \
libskia \
libstagefright \
+ libstagefright_foundation \
libbinder \
libutils \
libjpeg
diff --git a/media/tests/omxjpegdecoder/SkOmxPixelRef.cpp b/media/tests/omxjpegdecoder/SkOmxPixelRef.cpp
index dfdf676..a25e854 100644
--- a/media/tests/omxjpegdecoder/SkOmxPixelRef.cpp
+++ b/media/tests/omxjpegdecoder/SkOmxPixelRef.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <SkBitmap.h>
#include "SkOmxPixelRef.h"
@@ -32,7 +32,7 @@
SkOmxPixelRef::~SkOmxPixelRef() {
mBuffer->release();
- CHECK_EQ(mDecoder->stop(), OK);
+ CHECK_EQ(mDecoder->stop(), (status_t)OK);
SkSafeUnref(mCTable);
}
diff --git a/media/tests/omxjpegdecoder/StreamSource.cpp b/media/tests/omxjpegdecoder/StreamSource.cpp
index 5f44203..f764121a 100644
--- a/media/tests/omxjpegdecoder/StreamSource.cpp
+++ b/media/tests/omxjpegdecoder/StreamSource.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
#include "StreamSource.h"
diff --git a/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp b/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp
index 42df66c..6424744 100644
--- a/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp
+++ b/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp
@@ -25,7 +25,7 @@
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <media/IMediaPlayerService.h>
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/OMXClient.h>
@@ -89,7 +89,7 @@
OmxJpegImageDecoder::OmxJpegImageDecoder() {
status_t err = mClient.connect();
- CHECK_EQ(err, OK);
+ CHECK_EQ(err, (status_t)OK);
}
OmxJpegImageDecoder::~OmxJpegImageDecoder() {
@@ -152,7 +152,7 @@
int64_t duration = getNowUs() - startTime;
if (err != OK) {
- CHECK_EQ(buffer, NULL);
+ CHECK(buffer == NULL);
}
printf("Duration in decoder->read(): %.1f (msecs). \n",
duration / 1E3 );
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 4ea2c31..3beaac9 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -43,6 +43,7 @@
<bool name="assisted_gps_enabled">true</bool>
<!-- 0 == mobile, 1 == wifi. -->
<integer name="def_network_preference">1</integer>
+ <bool name="def_netstats_enabled">true</bool>
<bool name="def_usb_mass_storage_enabled">true</bool>
<bool name="def_wifi_on">false</bool>
<bool name="def_networks_available_notification_on">true</bool>
@@ -70,6 +71,8 @@
<integer name="def_lockscreen_sounds_enabled">1</integer>
<string name="def_lock_sound" translatable="false">/system/media/audio/ui/Lock.ogg</string>
<string name="def_unlock_sound" translatable="false">/system/media/audio/ui/Unlock.ogg</string>
+ <bool name="def_lockscreen_disabled">false</bool>
+ <bool name="def_device_provisioned">false</bool>
<!-- Notifications use ringer volume -->
<bool name="def_notifications_use_ring_volume">true</bool>
@@ -141,4 +144,8 @@
<bool name="def_dtmf_tones_enabled">true</bool>
<!-- Default for UI touch sounds enabled -->
<bool name="def_sound_effects_enabled">true</bool>
+
+ <!-- Development settings -->
+ <bool name="def_stay_on_while_plugged_in">false</bool>
+
</resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 6e9ea52..882aa66 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -63,7 +63,7 @@
// database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
// is properly propagated through your change. Not doing so will result in a loss of user
// settings.
- private static final int DATABASE_VERSION = 75;
+ private static final int DATABASE_VERSION = 76;
private Context mContext;
@@ -1006,6 +1006,29 @@
}
upgradeVersion = 75;
}
+ if (upgradeVersion == 75) {
+ db.beginTransaction();
+ SQLiteStatement stmt = null;
+ Cursor c = null;
+ try {
+ c = db.query("secure", new String[] {"_id", "value"},
+ "name='lockscreen.disabled'",
+ null, null, null, null);
+ // only set default if it has not yet been set
+ if (c == null || c.getCount() == 0) {
+ stmt = db.compileStatement("INSERT INTO system(name,value)"
+ + " VALUES(?,?);");
+ loadBooleanSetting(stmt, Settings.System.LOCKSCREEN_DISABLED,
+ R.bool.def_lockscreen_disabled);
+ }
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ if (c != null) c.close();
+ if (stmt != null) stmt.close();
+ }
+ upgradeVersion = 76;
+ }
// *** Remember to update DATABASE_VERSION above!
@@ -1352,7 +1375,9 @@
loadBooleanSetting(stmt, Settings.System.DIM_SCREEN,
R.bool.def_dim_screen);
loadSetting(stmt, Settings.System.STAY_ON_WHILE_PLUGGED_IN,
- "1".equals(SystemProperties.get("ro.kernel.qemu")) ? 1 : 0);
+ ("1".equals(SystemProperties.get("ro.kernel.qemu")) ||
+ mContext.getResources().getBoolean(R.bool.def_stay_on_while_plugged_in))
+ ? 1 : 0);
loadIntegerSetting(stmt, Settings.System.SCREEN_OFF_TIMEOUT,
R.integer.def_screen_off_timeout);
@@ -1568,6 +1593,15 @@
loadStringSetting(stmt, Settings.Secure.ACCESSIBILITY_SCREEN_READER_URL,
R.string.def_accessibility_screen_reader_url);
+
+ loadBooleanSetting(stmt, Settings.System.LOCKSCREEN_DISABLED,
+ R.bool.def_lockscreen_disabled);
+
+ loadBooleanSetting(stmt, Settings.Secure.DEVICE_PROVISIONED,
+ R.bool.def_device_provisioned);
+
+ loadBooleanSetting(stmt, Settings.Secure.NETSTATS_ENABLED,
+ R.bool.def_netstats_enabled);
} finally {
if (stmt != null) stmt.close();
}
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index a5bfb4a..16bb040 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -65,7 +65,7 @@
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Kuvatõmmise salvestamine ..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Kuvatõmmise salvestamine ..."</string>
<string name="screenshot_saving_text" msgid="2419718443411738818">"Kuvatõmmist salvestatakse."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"Kuvatõmmis on jäädvustatud."</string>
+ <string name="screenshot_saved_title" msgid="6461865960961414961">"Ekraanipilt on jäädvustatud."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Puudutage kuvatõmmise vaatamiseks."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Kuvatõmmist ei saanud jäädvustada."</string>
<string name="screenshot_failed_text" msgid="8134011269572415402">"Kuvatõmmist ei saa salvestada. Mäluseade võib olla kasutuses."</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 39b428a..0249e89 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -36,7 +36,7 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Izaziso"</string>
<string name="battery_low_title" msgid="2783104807551211639">"Xhuma ishaja."</string>
<string name="battery_low_subtitle" msgid="1752040062087829196">"Ibhetri iya ngokuphela."</string>
- <string name="battery_low_percent_format" msgid="1077244949318261761">"okusele okungu-<xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> okusele"</string>
<string name="invalid_charger" msgid="4549105996740522523">"Ukushaja i-USB akusekelwe."\n"Sebenzisa kuphela ishaja enikeziwe."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Ukusebenzisa ibhetri"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Izilungiselelo"</string>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index 6287408..5151cad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -456,8 +456,7 @@
// Sanity-check that someone hasn't set up the config wrong and asked for a navigation
// bar on a tablet that has only the system bar
if (mWindowManager.hasNavigationBar()) {
- throw new RuntimeException(
- "Tablet device cannot show navigation bar and system bar");
+ Slog.e(TAG, "Tablet device cannot show navigation bar and system bar");
}
} catch (RemoteException ex) {
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java b/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java
index abed18f..83f7788 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java
@@ -52,8 +52,7 @@
}
public void preDispatchKeyEvent(KeyEvent event) {
- getAudioManager().preDispatchKeyEvent(event.getKeyCode(),
- AudioManager.USE_DEFAULT_STREAM_TYPE);
+ getAudioManager().preDispatchKeyEvent(event, AudioManager.USE_DEFAULT_STREAM_TYPE);
}
public boolean dispatchKeyEvent(KeyEvent event) {
@@ -79,7 +78,7 @@
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_MUTE: {
- getAudioManager().handleKeyDown(keyCode, AudioManager.USE_DEFAULT_STREAM_TYPE);
+ getAudioManager().handleKeyDown(event, AudioManager.USE_DEFAULT_STREAM_TYPE);
return true;
}
@@ -197,8 +196,7 @@
AudioManager audioManager = (AudioManager)mContext.getSystemService(
Context.AUDIO_SERVICE);
if (audioManager != null) {
- getAudioManager().handleKeyUp(keyCode,
- AudioManager.USE_DEFAULT_STREAM_TYPE);
+ getAudioManager().handleKeyUp(event, AudioManager.USE_DEFAULT_STREAM_TYPE);
}
}
return true;
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index f1fe43b7..b87b8c3 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -1416,7 +1416,7 @@
// doesn't have one of these. In this case, we execute it here and
// eat the event instead, because we have mVolumeControlStreamType
// and they don't.
- getAudioManager().handleKeyDown(keyCode, mVolumeControlStreamType);
+ getAudioManager().handleKeyDown(event, mVolumeControlStreamType);
return true;
}
@@ -1478,7 +1478,7 @@
// doesn't have one of these. In this case, we execute it here and
// eat the event instead, because we have mVolumeControlStreamType
// and they don't.
- getAudioManager().handleKeyUp(keyCode, mVolumeControlStreamType);
+ getAudioManager().handleKeyUp(event, mVolumeControlStreamType);
return true;
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index d34ed177..c12a4b7e 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -286,7 +286,8 @@
/** If true, hitting shift & menu will broadcast Intent.ACTION_BUG_REPORT */
boolean mEnableShiftMenuBugReports = false;
-
+
+ boolean mHeadless;
boolean mSafeMode;
WindowState mStatusBar = null;
boolean mStatusBarCanHide;
@@ -686,7 +687,7 @@
if (mGlobalActions == null) {
mGlobalActions = new GlobalActions(mContext);
}
- final boolean keyguardShowing = mKeyguardMediator.isShowingAndNotHidden();
+ final boolean keyguardShowing = keyguardIsShowingTq();
mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());
if (keyguardShowing) {
// since it took two seconds of long press to bring this up,
@@ -783,7 +784,11 @@
mWindowManager = windowManager;
mWindowManagerFuncs = windowManagerFuncs;
mPowerManager = powerManager;
- mKeyguardMediator = new KeyguardViewMediator(context, this, powerManager);
+ mHeadless = "1".equals(SystemProperties.get("ro.config.headless", "0"));
+ if (!mHeadless) {
+ // don't create KeyguardViewMediator if headless
+ mKeyguardMediator = new KeyguardViewMediator(context, this, powerManager);
+ }
mHandler = new Handler();
mOrientationListener = new MyOrientationListener(mContext);
try {
@@ -1511,12 +1516,8 @@
}
static ITelephony getTelephonyService() {
- ITelephony telephonyService = ITelephony.Stub.asInterface(
+ return ITelephony.Stub.asInterface(
ServiceManager.checkService(Context.TELEPHONY_SERVICE));
- if (telephonyService == null) {
- Log.w(TAG, "Unable to find ITelephony interface.");
- }
- return telephonyService;
}
static IAudioService getAudioService() {
@@ -1839,7 +1840,7 @@
* given the situation with the keyguard.
*/
void launchHomeFromHotKey() {
- if (mKeyguardMediator.isShowingAndNotHidden()) {
+ if (mKeyguardMediator != null && mKeyguardMediator.isShowingAndNotHidden()) {
// don't launch home if keyguard showing
} else if (!mHideLockScreen && mKeyguardMediator.isInputRestricted()) {
// when in keyguard restricted mode, must first verify unlock
@@ -2580,6 +2581,9 @@
/** {@inheritDoc} */
public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) {
+ // do nothing if headless
+ if (mHeadless) return;
+
// lid changed state
mLidOpen = lidOpen ? LID_OPEN : LID_CLOSED;
updateKeyboardVisibility();
@@ -2776,9 +2780,10 @@
// the same as if it were open and in front.
// This will prevent any keys other than the power button from waking the screen
// when the keyguard is hidden by another activity.
- final boolean keyguardActive = (isScreenOn ?
- mKeyguardMediator.isShowingAndNotHidden() :
- mKeyguardMediator.isShowing());
+ final boolean keyguardActive = (mKeyguardMediator == null ? false :
+ (isScreenOn ?
+ mKeyguardMediator.isShowingAndNotHidden() :
+ mKeyguardMediator.isShowing()));
if (!mSystemBooted) {
// If we have not yet booted, don't let key events do anything.
@@ -2810,7 +2815,7 @@
// the device some other way (which is why we have an exemption here for injected
// events).
int result;
- if (isScreenOn || (isInjected && !isWakeKey)) {
+ if ((isScreenOn && !mHeadless) || (isInjected && !isWakeKey)) {
// When the screen is on or if the key is injected pass the key to the application.
result = ACTION_PASS_TO_USER;
} else {
@@ -3046,7 +3051,7 @@
final boolean isWakeMotion = (policyFlags
& (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
if (isWakeMotion) {
- if (mKeyguardMediator.isShowing()) {
+ if (mKeyguardMediator != null && mKeyguardMediator.isShowing()) {
// If the keyguard is showing, let it decide what to do with the wake motion.
mKeyguardMediator.onWakeMotionWhenKeyguardShowingTq();
} else {
@@ -3114,7 +3119,9 @@
mScreenOnEarly = false;
mScreenOnFully = false;
}
- mKeyguardMediator.onScreenTurnedOff(why);
+ if (mKeyguardMediator != null) {
+ mKeyguardMediator.onScreenTurnedOff(why);
+ }
synchronized (mLock) {
updateOrientationListenerLp();
updateLockScreenTimeout();
@@ -3131,31 +3138,33 @@
Slog.i(TAG, "Screen turning on...", here);
}
if (screenOnListener != null) {
- mKeyguardMediator.onScreenTurnedOn(new KeyguardViewManager.ShowListener() {
- @Override public void onShown(IBinder windowToken) {
- if (windowToken != null) {
- try {
- mWindowManager.waitForWindowDrawn(windowToken,
- new IRemoteCallback.Stub() {
- @Override public void sendResult(Bundle data) {
- Slog.i(TAG, "Lock screen displayed!");
- screenOnListener.onScreenOn();
- synchronized (mLock) {
- mScreenOnFully = true;
+ if (mKeyguardMediator != null) {
+ mKeyguardMediator.onScreenTurnedOn(new KeyguardViewManager.ShowListener() {
+ @Override public void onShown(IBinder windowToken) {
+ if (windowToken != null) {
+ try {
+ mWindowManager.waitForWindowDrawn(windowToken,
+ new IRemoteCallback.Stub() {
+ @Override public void sendResult(Bundle data) {
+ Slog.i(TAG, "Lock screen displayed!");
+ screenOnListener.onScreenOn();
+ synchronized (mLock) {
+ mScreenOnFully = true;
+ }
}
- }
- });
- } catch (RemoteException e) {
- }
- } else {
- Slog.i(TAG, "No lock screen!");
- screenOnListener.onScreenOn();
- synchronized (mLock) {
- mScreenOnFully = true;
+ });
+ } catch (RemoteException e) {
+ }
+ } else {
+ Slog.i(TAG, "No lock screen!");
+ screenOnListener.onScreenOn();
+ synchronized (mLock) {
+ mScreenOnFully = true;
+ }
}
}
- }
- });
+ });
+ }
} else {
synchronized (mLock) {
mScreenOnFully = true;
@@ -3181,15 +3190,20 @@
/** {@inheritDoc} */
public void enableKeyguard(boolean enabled) {
- mKeyguardMediator.setKeyguardEnabled(enabled);
+ if (mKeyguardMediator != null) {
+ mKeyguardMediator.setKeyguardEnabled(enabled);
+ }
}
/** {@inheritDoc} */
public void exitKeyguardSecurely(OnKeyguardExitResult callback) {
- mKeyguardMediator.verifyUnlock(callback);
+ if (mKeyguardMediator != null) {
+ mKeyguardMediator.verifyUnlock(callback);
+ }
}
private boolean keyguardIsShowingTq() {
+ if (mKeyguardMediator == null) return false;
return mKeyguardMediator.isShowingAndNotHidden();
}
@@ -3201,11 +3215,13 @@
/** {@inheritDoc} */
public boolean isKeyguardSecure() {
+ if (mKeyguardMediator == null) return false;
return mKeyguardMediator.isSecure();
}
/** {@inheritDoc} */
public boolean inKeyguardRestrictedKeyInputMode() {
+ if (mKeyguardMediator == null) return false;
return mKeyguardMediator.isInputRestricted();
}
@@ -3461,8 +3477,10 @@
/** {@inheritDoc} */
public void systemReady() {
- // tell the keyguard
- mKeyguardMediator.onSystemReady();
+ if (mKeyguardMediator != null) {
+ // tell the keyguard
+ mKeyguardMediator.onSystemReady();
+ }
synchronized (mLock) {
updateOrientationListenerLp();
mSystemReady = true;
@@ -3485,6 +3503,7 @@
/** {@inheritDoc} */
public void showBootMessage(final CharSequence msg, final boolean always) {
+ if (mHeadless) return;
mHandler.post(new Runnable() {
@Override public void run() {
if (mBootMsgDialog == null) {
@@ -3648,7 +3667,9 @@
public void run() {
synchronized (this) {
if (localLOGV) Log.v(TAG, "mScreenLockTimeout activating keyguard");
- mKeyguardMediator.doKeyguardTimeout();
+ if (mKeyguardMediator != null) {
+ mKeyguardMediator.doKeyguardTimeout();
+ }
mLockScreenTimerActive = false;
}
}
@@ -3662,7 +3683,8 @@
private void updateLockScreenTimeout() {
synchronized (mScreenLockTimeout) {
- boolean enable = (mAllowLockscreenWhenOn && mScreenOnEarly && mKeyguardMediator.isSecure());
+ boolean enable = (mAllowLockscreenWhenOn && mScreenOnEarly &&
+ mKeyguardMediator != null && mKeyguardMediator.isSecure());
if (mLockScreenTimerActive != enable) {
if (enable) {
if (localLOGV) Log.v(TAG, "setting lockscreen timer");
@@ -3862,7 +3884,7 @@
public void screenOnStoppedLw() {
if (mPowerManager.isScreenOn()) {
- if (!mKeyguardMediator.isShowingAndNotHidden()) {
+ if (mKeyguardMediator != null && !mKeyguardMediator.isShowingAndNotHidden()) {
long curTime = SystemClock.uptimeMillis();
mPowerManager.userActivity(curTime, false, LocalPowerManager.OTHER_EVENT);
}
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 52834db..deeb2de 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -6,9 +6,9 @@
AudioFlinger.cpp \
AudioMixer.cpp.arm \
AudioResampler.cpp.arm \
- AudioResamplerSinc.cpp.arm \
- AudioResamplerCubic.cpp.arm \
AudioPolicyService.cpp
+# AudioResamplerSinc.cpp.arm
+# AudioResamplerCubic.cpp.arm
LOCAL_C_INCLUDES := \
system/media/audio_effects/include \
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index f71ba0a..bbc9196 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -188,29 +188,32 @@
mod->name, mod->id);
mAudioHwDevs.push(dev);
- if (!mPrimaryHardwareDev) {
+ if (mPrimaryHardwareDev == NULL) {
mPrimaryHardwareDev = dev;
ALOGI("Using '%s' (%s.%s) as the primary audio interface",
mod->name, mod->id, audio_interfaces[i]);
}
}
- mHardwareStatus = AUDIO_HW_INIT;
-
- if (!mPrimaryHardwareDev || mAudioHwDevs.size() == 0) {
+ if (mPrimaryHardwareDev == NULL) {
ALOGE("Primary audio interface not found");
- return;
+ // proceed, all later accesses to mPrimaryHardwareDev verify it's safe with initCheck()
}
+ // Currently (mPrimaryHardwareDev == NULL) == (mAudioHwDevs.size() == 0), but the way the
+ // primary HW dev is selected can change so these conditions might not always be equivalent.
+ // When that happens, re-visit all the code that assumes this.
+
+ AutoMutex lock(mHardwareLock);
+
for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
audio_hw_device_t *dev = mAudioHwDevs[i];
mHardwareStatus = AUDIO_HW_INIT;
rc = dev->init_check(dev);
+ mHardwareStatus = AUDIO_HW_IDLE;
if (rc == 0) {
- AutoMutex lock(mHardwareLock);
-
- mMode = AUDIO_MODE_NORMAL;
+ mMode = AUDIO_MODE_NORMAL; // assigned multiple times with same value
mHardwareStatus = AUDIO_HW_SET_MODE;
dev->set_mode(dev, mMode);
mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
@@ -220,17 +223,8 @@
}
}
-status_t AudioFlinger::initCheck() const
-{
- Mutex::Autolock _l(mLock);
- if (mPrimaryHardwareDev == NULL || mAudioHwDevs.size() == 0)
- return NO_INIT;
- return NO_ERROR;
-}
-
AudioFlinger::~AudioFlinger()
{
- int num_devs = mAudioHwDevs.size();
while (!mRecordThreads.isEmpty()) {
// closeInput() will remove first entry from mRecordThreads
@@ -241,11 +235,10 @@
closeOutput(mPlaybackThreads.keyAt(0));
}
- for (int i = 0; i < num_devs; i++) {
- audio_hw_device_t *dev = mAudioHwDevs[i];
- audio_hw_device_close(dev);
+ for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
+ // no mHardwareLock needed, as there are no other references to this
+ audio_hw_device_close(mAudioHwDevs[i]);
}
- mAudioHwDevs.clear();
}
audio_hw_device_t* AudioFlinger::findSuitableHwDev_l(uint32_t devices)
@@ -371,6 +364,18 @@
return NO_ERROR;
}
+sp<AudioFlinger::Client> AudioFlinger::registerPid_l(pid_t pid)
+{
+ // If pid is already in the mClients wp<> map, then use that entry
+ // (for which promote() is always != 0), otherwise create a new entry and Client.
+ sp<Client> client = mClients.valueFor(pid).promote();
+ if (client == 0) {
+ client = new Client(this, pid);
+ mClients.add(pid, client);
+ }
+
+ return client;
+}
// IAudioFlinger interface
@@ -384,14 +389,13 @@
int frameCount,
uint32_t flags,
const sp<IMemory>& sharedBuffer,
- int output,
+ audio_io_handle_t output,
int *sessionId,
status_t *status)
{
sp<PlaybackThread::Track> track;
sp<TrackHandle> trackHandle;
sp<Client> client;
- wp<Client> wclient;
status_t lStatus;
int lSessionId;
@@ -413,14 +417,7 @@
goto Exit;
}
- wclient = mClients.valueFor(pid);
-
- if (wclient != NULL) {
- client = wclient.promote();
- } else {
- client = new Client(this, pid);
- mClients.add(pid, client);
- }
+ client = registerPid_l(pid);
ALOGV("createTrack() sessionId: %d", (sessionId == NULL) ? -2 : *sessionId);
if (sessionId != NULL && *sessionId != AUDIO_SESSION_OUTPUT_MIX) {
@@ -477,7 +474,7 @@
return trackHandle;
}
-uint32_t AudioFlinger::sampleRate(int output) const
+uint32_t AudioFlinger::sampleRate(audio_io_handle_t output) const
{
Mutex::Autolock _l(mLock);
PlaybackThread *thread = checkPlaybackThread_l(output);
@@ -488,7 +485,7 @@
return thread->sampleRate();
}
-int AudioFlinger::channelCount(int output) const
+int AudioFlinger::channelCount(audio_io_handle_t output) const
{
Mutex::Autolock _l(mLock);
PlaybackThread *thread = checkPlaybackThread_l(output);
@@ -499,7 +496,7 @@
return thread->channelCount();
}
-audio_format_t AudioFlinger::format(int output) const
+audio_format_t AudioFlinger::format(audio_io_handle_t output) const
{
Mutex::Autolock _l(mLock);
PlaybackThread *thread = checkPlaybackThread_l(output);
@@ -510,7 +507,7 @@
return thread->format();
}
-size_t AudioFlinger::frameCount(int output) const
+size_t AudioFlinger::frameCount(audio_io_handle_t output) const
{
Mutex::Autolock _l(mLock);
PlaybackThread *thread = checkPlaybackThread_l(output);
@@ -521,7 +518,7 @@
return thread->frameCount();
}
-uint32_t AudioFlinger::latency(int output) const
+uint32_t AudioFlinger::latency(audio_io_handle_t output) const
{
Mutex::Autolock _l(mLock);
PlaybackThread *thread = checkPlaybackThread_l(output);
@@ -622,6 +619,7 @@
}
bool state = AUDIO_MODE_INVALID;
+ AutoMutex lock(mHardwareLock);
mHardwareStatus = AUDIO_HW_GET_MIC_MUTE;
mPrimaryHardwareDev->get_mic_mute(mPrimaryHardwareDev, &state);
mHardwareStatus = AUDIO_HW_IDLE;
@@ -655,7 +653,8 @@
return masterMute_l();
}
-status_t AudioFlinger::setStreamVolume(audio_stream_type_t stream, float value, int output)
+status_t AudioFlinger::setStreamVolume(audio_stream_type_t stream, float value,
+ audio_io_handle_t output)
{
// check calling permissions
if (!settingsAllowed()) {
@@ -710,7 +709,7 @@
return NO_ERROR;
}
-float AudioFlinger::streamVolume(audio_stream_type_t stream, int output) const
+float AudioFlinger::streamVolume(audio_stream_type_t stream, audio_io_handle_t output) const
{
if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
return 0.0f;
@@ -740,11 +739,11 @@
return mStreamTypes[stream].mute;
}
-status_t AudioFlinger::setParameters(int ioHandle, const String8& keyValuePairs)
+status_t AudioFlinger::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs)
{
status_t result;
- ALOGV("setParameters(): io %d, keyvalue %s, tid %d, calling tid %d",
+ ALOGV("setParameters(): io %d, keyvalue %s, tid %d, calling pid %d",
ioHandle, keyValuePairs.string(), gettid(), IPCThreadState::self()->getCallingPid());
// check calling permissions
if (!settingsAllowed()) {
@@ -809,16 +808,15 @@
}
}
}
- if (thread != NULL) {
- result = thread->setParameters(keyValuePairs);
- return result;
+ if (thread != 0) {
+ return thread->setParameters(keyValuePairs);
}
return BAD_VALUE;
}
-String8 AudioFlinger::getParameters(int ioHandle, const String8& keys)
+String8 AudioFlinger::getParameters(audio_io_handle_t ioHandle, const String8& keys) const
{
-// ALOGV("getParameters() io %d, keys %s, tid %d, calling tid %d",
+// ALOGV("getParameters() io %d, keys %s, tid %d, calling pid %d",
// ioHandle, keys.string(), gettid(), IPCThreadState::self()->getCallingPid());
if (ioHandle == 0) {
@@ -846,17 +844,21 @@
return String8("");
}
-size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, audio_format_t format, int channelCount)
+size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, audio_format_t format, int channelCount) const
{
status_t ret = initCheck();
if (ret != NO_ERROR) {
return 0;
}
- return mPrimaryHardwareDev->get_input_buffer_size(mPrimaryHardwareDev, sampleRate, format, channelCount);
+ AutoMutex lock(mHardwareLock);
+ mHardwareStatus = AUDIO_HW_GET_INPUT_BUFFER_SIZE;
+ size_t size = mPrimaryHardwareDev->get_input_buffer_size(mPrimaryHardwareDev, sampleRate, format, channelCount);
+ mHardwareStatus = AUDIO_HW_IDLE;
+ return size;
}
-unsigned int AudioFlinger::getInputFramesLost(int ioHandle)
+unsigned int AudioFlinger::getInputFramesLost(audio_io_handle_t ioHandle) const
{
if (ioHandle == 0) {
return 0;
@@ -891,7 +893,8 @@
return ret;
}
-status_t AudioFlinger::getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, int output)
+status_t AudioFlinger::getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames,
+ audio_io_handle_t output) const
{
status_t status;
@@ -910,7 +913,7 @@
Mutex::Autolock _l(mLock);
- int pid = IPCThreadState::self()->getCallingPid();
+ pid_t pid = IPCThreadState::self()->getCallingPid();
if (mNotificationClients.indexOfKey(pid) < 0) {
sp<NotificationClient> notificationClient = new NotificationClient(this,
client,
@@ -966,7 +969,7 @@
}
// audioConfigChanged_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::audioConfigChanged_l(int event, int ioHandle, void *param2)
+void AudioFlinger::audioConfigChanged_l(int event, audio_io_handle_t ioHandle, void *param2)
{
size_t size = mNotificationClients.size();
for (size_t i = 0; i < size; i++) {
@@ -985,8 +988,8 @@
// ----------------------------------------------------------------------------
-AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, int id, uint32_t device,
- type_t type)
+AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
+ uint32_t device, type_t type)
: Thread(false),
mType(type),
mAudioFlinger(audioFlinger), mSampleRate(0), mFrameCount(0),
@@ -994,7 +997,7 @@
mChannelCount(0),
mFrameSize(1), mFormat(AUDIO_FORMAT_INVALID),
mParamStatus(NO_ERROR),
- mStandby(false), mId(id), mExiting(false),
+ mStandby(false), mId(id),
mDevice(device),
mDeathRecipient(new PMDeathRecipient(this))
{
@@ -1013,40 +1016,26 @@
void AudioFlinger::ThreadBase::exit()
{
- // keep a strong ref on ourself so that we won't get
- // destroyed in the middle of requestExitAndWait()
- sp <ThreadBase> strongMe = this;
-
ALOGV("ThreadBase::exit");
{
+ // This lock prevents the following race in thread (uniprocessor for illustration):
+ // if (!exitPending()) {
+ // // context switch from here to exit()
+ // // exit() calls requestExit(), what exitPending() observes
+ // // exit() calls signal(), which is dropped since no waiters
+ // // context switch back from exit() to here
+ // mWaitWorkCV.wait(...);
+ // // now thread is hung
+ // }
AutoMutex lock(mLock);
- mExiting = true;
requestExit();
mWaitWorkCV.signal();
}
+ // When Thread::requestExitAndWait is made virtual and this method is renamed to
+ // "virtual status_t requestExitAndWait()", replace by "return Thread::requestExitAndWait();"
requestExitAndWait();
}
-uint32_t AudioFlinger::ThreadBase::sampleRate() const
-{
- return mSampleRate;
-}
-
-int AudioFlinger::ThreadBase::channelCount() const
-{
- return (int)mChannelCount;
-}
-
-audio_format_t AudioFlinger::ThreadBase::format() const
-{
- return mFormat;
-}
-
-size_t AudioFlinger::ThreadBase::frameCount() const
-{
- return mFrameCount;
-}
-
status_t AudioFlinger::ThreadBase::setParameters(const String8& keyValuePairs)
{
status_t status;
@@ -1248,8 +1237,7 @@
void AudioFlinger::ThreadBase::setEffectSuspended_l(
const effect_uuid_t *type, bool suspend, int sessionId)
{
- sp<EffectChain> chain;
- chain = getEffectChain_l(sessionId);
+ sp<EffectChain> chain = getEffectChain_l(sessionId);
if (chain != 0) {
if (type != NULL) {
chain->setEffectSuspended_l(type, suspend);
@@ -1377,7 +1365,7 @@
AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger,
AudioStreamOut* output,
- int id,
+ audio_io_handle_t id,
uint32_t device,
type_t type)
: ThreadBase(audioFlinger, id, device, type),
@@ -1541,12 +1529,11 @@
// all tracks in same audio session must share the same routing strategy otherwise
// conflicts will happen when tracks are moved from one output to another by audio policy
// manager
- uint32_t strategy =
- AudioSystem::getStrategyForStream((audio_stream_type_t)streamType);
+ uint32_t strategy = AudioSystem::getStrategyForStream(streamType);
for (size_t i = 0; i < mTracks.size(); ++i) {
sp<Track> t = mTracks[i];
if (t != 0) {
- uint32_t actual = AudioSystem::getStrategyForStream((audio_stream_type_t)t->type());
+ uint32_t actual = AudioSystem::getStrategyForStream(t->streamType());
if (sessionId == t->sessionId() && strategy != actual) {
ALOGE("createTrack_l() mismatched strategy; expected %u but found %u",
strategy, actual);
@@ -1568,7 +1555,7 @@
if (chain != 0) {
ALOGV("createTrack_l() setting main buffer %p", chain->inBuffer());
track->setMainBuffer(chain->inBuffer());
- chain->setStrategy(AudioSystem::getStrategyForStream((audio_stream_type_t)track->type()));
+ chain->setStrategy(AudioSystem::getStrategyForStream(track->streamType()));
chain->incTrackCnt();
}
@@ -1611,16 +1598,6 @@
return NO_ERROR;
}
-float AudioFlinger::PlaybackThread::masterVolume() const
-{
- return mMasterVolume;
-}
-
-bool AudioFlinger::PlaybackThread::masterMute() const
-{
- return mMasterMute;
-}
-
status_t AudioFlinger::PlaybackThread::setStreamVolume(audio_stream_type_t stream, float value)
{
mStreamTypes[stream].volume = value;
@@ -1808,7 +1785,7 @@
sp<Track> track = mTracks[i];
if (sessionId == track->sessionId() &&
!(track->mCblk->flags & CBLK_INVALID_MSK)) {
- return AudioSystem::getStrategyForStream((audio_stream_type_t) track->type());
+ return AudioSystem::getStrategyForStream(track->streamType());
}
}
return AudioSystem::getStrategyForStream(AUDIO_STREAM_MUSIC);
@@ -1853,7 +1830,7 @@
// ----------------------------------------------------------------------------
AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
- int id, uint32_t device, type_t type)
+ audio_io_handle_t id, uint32_t device, type_t type)
: PlaybackThread(audioFlinger, output, id, device, type),
mAudioMixer(new AudioMixer(mFrameCount, mSampleRate)),
mPrevMixerStatus(MIXER_IDLE)
@@ -1947,7 +1924,7 @@
if (CC_UNLIKELY((!activeTracks.size() && systemTime() > standbyTime) ||
mSuspended)) {
if (!mStandby) {
- ALOGV("Audio hardware entering standby, mixer %p, mSuspended %d\n", this, mSuspended);
+ ALOGV("Audio hardware entering standby, mixer %p, mSuspended %d", this, mSuspended);
mOutput->stream->common.standby(&mOutput->stream->common);
mStandby = true;
mBytesWritten = 0;
@@ -1961,9 +1938,9 @@
releaseWakeLock_l();
// wait until we have something to do...
- ALOGV("MixerThread %p TID %d going to sleep\n", this, gettid());
+ ALOGV("MixerThread %p TID %d going to sleep", this, gettid());
mWaitWorkCV.wait(mLock);
- ALOGV("MixerThread %p TID %d waking up\n", this, gettid());
+ ALOGV("MixerThread %p TID %d waking up", this, gettid());
acquireWakeLock_l();
mPrevMixerStatus = MIXER_IDLE;
@@ -2189,7 +2166,7 @@
// compute volume for this track
uint32_t vl, vr, va;
if (track->isMuted() || track->isPausing() ||
- mStreamTypes[track->type()].mute) {
+ mStreamTypes[track->streamType()].mute) {
vl = vr = va = 0;
if (track->isPausing()) {
track->setPaused();
@@ -2197,7 +2174,7 @@
} else {
// read original volumes with volume control
- float typeVolume = mStreamTypes[track->type()].volume;
+ float typeVolume = mStreamTypes[track->streamType()].volume;
float v = masterVolume * typeVolume;
uint32_t vlr = cblk->getVolumeLR();
vl = vlr & 0xFFFF;
@@ -2358,7 +2335,7 @@
size_t size = mTracks.size();
for (size_t i = 0; i < size; i++) {
sp<Track> t = mTracks[i];
- if (t->type() == streamType) {
+ if (t->streamType() == streamType) {
android_atomic_or(CBLK_INVALID_ON, &t->mCblk->flags);
t->mCblk->cv.signal();
}
@@ -2520,7 +2497,8 @@
}
// ----------------------------------------------------------------------------
-AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device)
+AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger,
+ AudioStreamOut* output, audio_io_handle_t id, uint32_t device)
: PlaybackThread(audioFlinger, output, id, device, DIRECT)
// mLeftVolFloat, mRightVolFloat
// mLeftVolShort, mRightVolShort
@@ -2531,21 +2509,6 @@
{
}
-static inline
-int32_t mul(int16_t in, int16_t v)
-{
-#if defined(__arm__) && !defined(__thumb__)
- int32_t out;
- asm( "smulbb %[out], %[in], %[v] \n"
- : [out]"=r"(out)
- : [in]"%r"(in), [v]"r"(v)
- : );
- return out;
-#else
- return in * int32_t(v);
-#endif
-}
-
void AudioFlinger::DirectOutputThread::applyVolume(uint16_t leftVol, uint16_t rightVol, bool ramp)
{
// Do not apply volume on compressed audio
@@ -2664,7 +2627,7 @@
mSuspended)) {
// wait until we have something to do...
if (!mStandby) {
- ALOGV("Audio hardware entering standby, mixer %p\n", this);
+ ALOGV("Audio hardware entering standby, mixer %p", this);
mOutput->stream->common.standby(&mOutput->stream->common);
mStandby = true;
mBytesWritten = 0;
@@ -2677,9 +2640,9 @@
if (exitPending()) break;
releaseWakeLock_l();
- ALOGV("DirectOutputThread %p TID %d going to sleep\n", this, gettid());
+ ALOGV("DirectOutputThread %p TID %d going to sleep", this, gettid());
mWaitWorkCV.wait(mLock);
- ALOGV("DirectOutputThread %p TID %d waking up in active mode\n", this, gettid());
+ ALOGV("DirectOutputThread %p TID %d waking up in active mode", this, gettid());
acquireWakeLock_l();
if (!mMasterMute) {
@@ -2730,13 +2693,13 @@
// compute volume for this track
float left, right;
if (track->isMuted() || mMasterMute || track->isPausing() ||
- mStreamTypes[track->type()].mute) {
+ mStreamTypes[track->streamType()].mute) {
left = right = 0;
if (track->isPausing()) {
track->setPaused();
}
} else {
- float typeVolume = mStreamTypes[track->type()].volume;
+ float typeVolume = mStreamTypes[track->streamType()].volume;
float v = mMasterVolume * typeVolume;
uint32_t vlr = cblk->getVolumeLR();
float v_clamped = v * (vlr & 0xFFFF);
@@ -3002,7 +2965,7 @@
// ----------------------------------------------------------------------------
AudioFlinger::DuplicatingThread::DuplicatingThread(const sp<AudioFlinger>& audioFlinger,
- AudioFlinger::MixerThread* mainThread, int id)
+ AudioFlinger::MixerThread* mainThread, audio_io_handle_t id)
: MixerThread(audioFlinger, mainThread->getOutput(), id, mainThread->device(), DUPLICATING),
mWaitTimeMs(UINT_MAX)
{
@@ -3014,7 +2977,6 @@
for (size_t i = 0; i < mOutputTracks.size(); i++) {
mOutputTracks[i]->destroy();
}
- mOutputTracks.clear();
}
bool AudioFlinger::DuplicatingThread::threadLoop()
@@ -3073,9 +3035,9 @@
if (exitPending()) break;
releaseWakeLock_l();
- ALOGV("DuplicatingThread %p TID %d going to sleep\n", this, gettid());
+ ALOGV("DuplicatingThread %p TID %d going to sleep", this, gettid());
mWaitWorkCV.wait(mLock);
- ALOGV("DuplicatingThread %p TID %d waking up\n", this, gettid());
+ ALOGV("DuplicatingThread %p TID %d waking up", this, gettid());
acquireWakeLock_l();
mPrevMixerStatus = MIXER_IDLE;
@@ -3206,7 +3168,7 @@
mWaitTimeMs = UINT_MAX;
for (size_t i = 0; i < mOutputTracks.size(); i++) {
sp<ThreadBase> strong = mOutputTracks[i]->thread().promote();
- if (strong != NULL) {
+ if (strong != 0) {
uint32_t waitTimeMs = (strong->frameCount() * 2 * 1000) / strong->sampleRate();
if (waitTimeMs < mWaitTimeMs) {
mWaitTimeMs = waitTimeMs;
@@ -3259,7 +3221,6 @@
// mBufferEnd
mFrameCount(0),
mState(IDLE),
- mClientTid(-1),
mFormat(format),
mFlags(flags & ~SYSTEM_FLAGS_MASK),
mSessionId(sessionId)
@@ -3324,15 +3285,19 @@
AudioFlinger::ThreadBase::TrackBase::~TrackBase()
{
if (mCblk != NULL) {
- mCblk->~audio_track_cblk_t(); // destroy our shared-structure.
- if (mClient == NULL) {
+ if (mClient == 0) {
delete mCblk;
+ } else {
+ mCblk->~audio_track_cblk_t(); // destroy our shared-structure.
}
}
- mCblkMemory.clear(); // and free the shared memory
- if (mClient != NULL) {
+ mCblkMemory.clear(); // free the shared memory before releasing the heap it belongs to
+ if (mClient != 0) {
// Client destructor must run with AudioFlinger mutex locked
Mutex::Autolock _l(mClient->audioFlinger()->mLock);
+ // If the client's reference count drops to zero, the associated destructor
+ // must run with AudioFlinger lock held. Thus the explicit clear() rather than
+ // relying on the automatic clear() at end of scope.
mClient.clear();
}
}
@@ -3368,23 +3333,10 @@
ALOGV("TrackBase::reset");
}
-sp<IMemory> AudioFlinger::ThreadBase::TrackBase::getCblk() const
-{
- return mCblkMemory;
-}
-
int AudioFlinger::ThreadBase::TrackBase::sampleRate() const {
return (int)mCblk->sampleRate;
}
-int AudioFlinger::ThreadBase::TrackBase::channelCount() const {
- return (const int)mChannelCount;
-}
-
-uint32_t AudioFlinger::ThreadBase::TrackBase::channelMask() const {
- return mChannelMask;
-}
-
void* AudioFlinger::ThreadBase::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const {
audio_track_cblk_t* cblk = this->cblk();
size_t frameSize = cblk->frameSize;
@@ -3428,7 +3380,7 @@
mName = playbackThread->getTrackName_l();
mMainBuffer = playbackThread->mixBuffer();
}
- ALOGV("Track constructor name %d, calling thread %d", mName, IPCThreadState::self()->getCallingPid());
+ ALOGV("Track constructor name %d, calling pid %d", mName, IPCThreadState::self()->getCallingPid());
if (mName < 0) {
ALOGE("no more track names available");
}
@@ -3465,9 +3417,7 @@
if (thread != 0) {
if (!isOutputTrack()) {
if (mState == ACTIVE || mState == RESUMING) {
- AudioSystem::stopOutput(thread->id(),
- (audio_stream_type_t)mStreamType,
- mSessionId);
+ AudioSystem::stopOutput(thread->id(), mStreamType, mSessionId);
// to track the speaker usage
addBatteryData(IMediaPlayerService::kBatteryDataAudioFlingerStop);
@@ -3486,7 +3436,7 @@
uint32_t vlr = mCblk->getVolumeLR();
snprintf(buffer, size, " %05d %05d %03u %03u 0x%08x %05u %04u %1d %1d %1d %05u %05u %05u 0x%08x 0x%08x 0x%08x 0x%08x\n",
mName - AudioMixer::TRACK0,
- (mClient == NULL) ? getpid() : mClient->pid(),
+ (mClient == 0) ? getpid() : mClient->pid(),
mStreamType,
mFormat,
mChannelMask,
@@ -3560,7 +3510,7 @@
status_t AudioFlinger::PlaybackThread::Track::start()
{
status_t status = NO_ERROR;
- ALOGV("start(%d), calling thread %d session %d",
+ ALOGV("start(%d), calling pid %d session %d",
mName, IPCThreadState::self()->getCallingPid(), mSessionId);
sp<ThreadBase> thread = mThread.promote();
if (thread != 0) {
@@ -3578,9 +3528,7 @@
if (!isOutputTrack() && state != ACTIVE && state != RESUMING) {
thread->mLock.unlock();
- status = AudioSystem::startOutput(thread->id(),
- (audio_stream_type_t)mStreamType,
- mSessionId);
+ status = AudioSystem::startOutput(thread->id(), mStreamType, mSessionId);
thread->mLock.lock();
// to track the speaker usage
@@ -3602,7 +3550,7 @@
void AudioFlinger::PlaybackThread::Track::stop()
{
- ALOGV("stop(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid());
+ ALOGV("stop(%d), calling pid %d", mName, IPCThreadState::self()->getCallingPid());
sp<ThreadBase> thread = mThread.promote();
if (thread != 0) {
Mutex::Autolock _l(thread->mLock);
@@ -3618,9 +3566,7 @@
}
if (!isOutputTrack() && (state == ACTIVE || state == RESUMING)) {
thread->mLock.unlock();
- AudioSystem::stopOutput(thread->id(),
- (audio_stream_type_t)mStreamType,
- mSessionId);
+ AudioSystem::stopOutput(thread->id(), mStreamType, mSessionId);
thread->mLock.lock();
// to track the speaker usage
@@ -3631,7 +3577,7 @@
void AudioFlinger::PlaybackThread::Track::pause()
{
- ALOGV("pause(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid());
+ ALOGV("pause(%d), calling pid %d", mName, IPCThreadState::self()->getCallingPid());
sp<ThreadBase> thread = mThread.promote();
if (thread != 0) {
Mutex::Autolock _l(thread->mLock);
@@ -3640,9 +3586,7 @@
ALOGV("ACTIVE/RESUMING => PAUSING (%d) on thread %p", mName, thread.get());
if (!isOutputTrack()) {
thread->mLock.unlock();
- AudioSystem::stopOutput(thread->id(),
- (audio_stream_type_t)mStreamType,
- mSessionId);
+ AudioSystem::stopOutput(thread->id(), mStreamType, mSessionId);
thread->mLock.lock();
// to track the speaker usage
@@ -3813,7 +3757,7 @@
void AudioFlinger::RecordThread::RecordTrack::dump(char* buffer, size_t size)
{
snprintf(buffer, size, " %05d %03u 0x%08x %05d %04u %01d %05u %08x %08x\n",
- (mClient == NULL) ? getpid() : mClient->pid(),
+ (mClient == 0) ? getpid() : mClient->pid(),
mFormat,
mChannelMask,
mSessionId,
@@ -4160,7 +4104,7 @@
sp<IAudioRecord> AudioFlinger::openRecord(
pid_t pid,
- int input,
+ audio_io_handle_t input,
uint32_t sampleRate,
audio_format_t format,
uint32_t channelMask,
@@ -4172,7 +4116,6 @@
sp<RecordThread::RecordTrack> recordTrack;
sp<RecordHandle> recordHandle;
sp<Client> client;
- wp<Client> wclient;
status_t lStatus;
RecordThread *thread;
size_t inFrameCount;
@@ -4193,13 +4136,7 @@
goto Exit;
}
- wclient = mClients.valueFor(pid);
- if (wclient != NULL) {
- client = wclient.promote();
- } else {
- client = new Client(this, pid);
- mClients.add(pid, client);
- }
+ client = registerPid_l(pid);
// If no audio session id is provided, create one here
if (sessionId != NULL && *sessionId != AUDIO_SESSION_OUTPUT_MIX) {
@@ -4277,7 +4214,7 @@
AudioStreamIn *input,
uint32_t sampleRate,
uint32_t channels,
- int id,
+ audio_io_handle_t id,
uint32_t device) :
ThreadBase(audioFlinger, id, device, RECORD),
mInput(input), mTrack(NULL), mResampler(NULL), mRsmpOutBuffer(NULL), mRsmpInBuffer(NULL),
@@ -4528,7 +4465,7 @@
track = new RecordTrack(this, client, sampleRate,
format, channelMask, frameCount, flags, sessionId);
- if (track->getCblk() == NULL) {
+ if (track->getCblk() == 0) {
lStatus = NO_MEMORY;
goto Exit;
}
@@ -4584,7 +4521,7 @@
ALOGV("Signal record thread");
mWaitWorkCV.signal();
// do not wait for mStartStopCond if exiting
- if (mExiting) {
+ if (exitPending()) {
mActiveTrack.clear();
status = INVALID_OPERATION;
goto startError;
@@ -4611,7 +4548,7 @@
if (mActiveTrack != 0 && recordTrack == mActiveTrack.get()) {
mActiveTrack->mState = TrackBase::PAUSING;
// do not wait for mStartStopCond if exiting
- if (mExiting) {
+ if (exitPending()) {
return;
}
mStartStopCond.wait(mLock);
@@ -4631,7 +4568,6 @@
const size_t SIZE = 256;
char buffer[SIZE];
String8 result;
- pid_t pid = 0;
snprintf(buffer, SIZE, "\nInput thread %p internals\n", this);
result.append(buffer);
@@ -4938,7 +4874,7 @@
// ----------------------------------------------------------------------------
-int AudioFlinger::openOutput(uint32_t *pDevices,
+audio_io_handle_t AudioFlinger::openOutput(uint32_t *pDevices,
uint32_t *pSamplingRate,
audio_format_t *pFormat,
uint32_t *pChannels,
@@ -4984,7 +4920,7 @@
mHardwareStatus = AUDIO_HW_IDLE;
if (outStream != NULL) {
AudioStreamOut *output = new AudioStreamOut(outHwDev, outStream);
- int id = nextUniqueId();
+ audio_io_handle_t id = nextUniqueId();
if ((flags & AUDIO_POLICY_OUTPUT_FLAG_DIRECT) ||
(format != AUDIO_FORMAT_PCM_16_BIT) ||
@@ -5010,7 +4946,8 @@
return 0;
}
-int AudioFlinger::openDuplicateOutput(int output1, int output2)
+audio_io_handle_t AudioFlinger::openDuplicateOutput(audio_io_handle_t output1,
+ audio_io_handle_t output2)
{
Mutex::Autolock _l(mLock);
MixerThread *thread1 = checkMixerThread_l(output1);
@@ -5021,7 +4958,7 @@
return 0;
}
- int id = nextUniqueId();
+ audio_io_handle_t id = nextUniqueId();
DuplicatingThread *thread = new DuplicatingThread(this, thread1, id);
thread->addOutputTrack(thread2);
mPlaybackThreads.add(id, thread);
@@ -5030,7 +4967,7 @@
return id;
}
-status_t AudioFlinger::closeOutput(int output)
+status_t AudioFlinger::closeOutput(audio_io_handle_t output)
{
// keep strong reference on the playback thread so that
// it is not destroyed while exit() is executed
@@ -5057,6 +4994,8 @@
mPlaybackThreads.removeItem(output);
}
thread->exit();
+ // The thread entity (active unit of execution) is no longer running here,
+ // but the ThreadBase container still exists.
if (thread->type() != ThreadBase::DUPLICATING) {
AudioStreamOut *out = thread->clearOutput();
@@ -5068,7 +5007,7 @@
return NO_ERROR;
}
-status_t AudioFlinger::suspendOutput(int output)
+status_t AudioFlinger::suspendOutput(audio_io_handle_t output)
{
Mutex::Autolock _l(mLock);
PlaybackThread *thread = checkPlaybackThread_l(output);
@@ -5083,7 +5022,7 @@
return NO_ERROR;
}
-status_t AudioFlinger::restoreOutput(int output)
+status_t AudioFlinger::restoreOutput(audio_io_handle_t output)
{
Mutex::Autolock _l(mLock);
PlaybackThread *thread = checkPlaybackThread_l(output);
@@ -5099,7 +5038,7 @@
return NO_ERROR;
}
-int AudioFlinger::openInput(uint32_t *pDevices,
+audio_io_handle_t AudioFlinger::openInput(uint32_t *pDevices,
uint32_t *pSamplingRate,
audio_format_t *pFormat,
uint32_t *pChannels,
@@ -5155,7 +5094,7 @@
if (inStream != NULL) {
AudioStreamIn *input = new AudioStreamIn(inHwDev, inStream);
- int id = nextUniqueId();
+ audio_io_handle_t id = nextUniqueId();
// Start record thread
// RecorThread require both input and output device indication to forward to audio
// pre processing modules
@@ -5182,7 +5121,7 @@
return 0;
}
-status_t AudioFlinger::closeInput(int input)
+status_t AudioFlinger::closeInput(audio_io_handle_t input)
{
// keep strong reference on the record thread so that
// it is not destroyed while exit() is executed
@@ -5200,6 +5139,8 @@
mRecordThreads.removeItem(input);
}
thread->exit();
+ // The thread entity (active unit of execution) is no longer running here,
+ // but the ThreadBase container still exists.
AudioStreamIn *in = thread->clearInput();
assert(in != NULL);
@@ -5210,7 +5151,7 @@
return NO_ERROR;
}
-status_t AudioFlinger::setStreamOutput(audio_stream_type_t stream, int output)
+status_t AudioFlinger::setStreamOutput(audio_stream_type_t stream, audio_io_handle_t output)
{
Mutex::Autolock _l(mLock);
MixerThread *dstThread = checkMixerThread_l(output);
@@ -5246,7 +5187,7 @@
void AudioFlinger::acquireAudioSessionId(int audioSession)
{
Mutex::Autolock _l(mLock);
- int caller = IPCThreadState::self()->getCallingPid();
+ pid_t caller = IPCThreadState::self()->getCallingPid();
ALOGV("acquiring %d from %d", audioSession, caller);
int num = mAudioSessionRefs.size();
for (int i = 0; i< num; i++) {
@@ -5264,7 +5205,7 @@
void AudioFlinger::releaseAudioSessionId(int audioSession)
{
Mutex::Autolock _l(mLock);
- int caller = IPCThreadState::self()->getCallingPid();
+ pid_t caller = IPCThreadState::self()->getCallingPid();
ALOGV("releasing %d from %d", audioSession, caller);
int num = mAudioSessionRefs.size();
for (int i = 0; i< num; i++) {
@@ -5348,7 +5289,7 @@
}
// checkPlaybackThread_l() must be called with AudioFlinger::mLock held
-AudioFlinger::PlaybackThread *AudioFlinger::checkPlaybackThread_l(int output) const
+AudioFlinger::PlaybackThread *AudioFlinger::checkPlaybackThread_l(audio_io_handle_t output) const
{
PlaybackThread *thread = NULL;
if (mPlaybackThreads.indexOfKey(output) >= 0) {
@@ -5358,7 +5299,7 @@
}
// checkMixerThread_l() must be called with AudioFlinger::mLock held
-AudioFlinger::MixerThread *AudioFlinger::checkMixerThread_l(int output) const
+AudioFlinger::MixerThread *AudioFlinger::checkMixerThread_l(audio_io_handle_t output) const
{
PlaybackThread *thread = checkPlaybackThread_l(output);
if (thread != NULL) {
@@ -5370,7 +5311,7 @@
}
// checkRecordThread_l() must be called with AudioFlinger::mLock held
-AudioFlinger::RecordThread *AudioFlinger::checkRecordThread_l(int input) const
+AudioFlinger::RecordThread *AudioFlinger::checkRecordThread_l(audio_io_handle_t input) const
{
RecordThread *thread = NULL;
if (mRecordThreads.indexOfKey(input) >= 0) {
@@ -5413,19 +5354,20 @@
// ----------------------------------------------------------------------------
-status_t AudioFlinger::queryNumberEffects(uint32_t *numEffects)
+status_t AudioFlinger::queryNumberEffects(uint32_t *numEffects) const
{
Mutex::Autolock _l(mLock);
return EffectQueryNumberEffects(numEffects);
}
-status_t AudioFlinger::queryEffect(uint32_t index, effect_descriptor_t *descriptor)
+status_t AudioFlinger::queryEffect(uint32_t index, effect_descriptor_t *descriptor) const
{
Mutex::Autolock _l(mLock);
return EffectQueryEffect(index, descriptor);
}
-status_t AudioFlinger::getEffectDescriptor(effect_uuid_t *pUuid, effect_descriptor_t *descriptor)
+status_t AudioFlinger::getEffectDescriptor(const effect_uuid_t *pUuid,
+ effect_descriptor_t *descriptor) const
{
Mutex::Autolock _l(mLock);
return EffectGetDescriptor(pUuid, descriptor);
@@ -5436,7 +5378,7 @@
effect_descriptor_t *pDesc,
const sp<IEffectClient>& effectClient,
int32_t priority,
- int io,
+ audio_io_handle_t io,
int sessionId,
status_t *status,
int *id,
@@ -5445,10 +5387,8 @@
status_t lStatus = NO_ERROR;
sp<EffectHandle> handle;
effect_descriptor_t desc;
- sp<Client> client;
- wp<Client> wclient;
- ALOGV("createEffect pid %d, client %p, priority %d, sessionId %d, io %d",
+ ALOGV("createEffect pid %d, effectClient %p, priority %d, sessionId %d, io %d",
pid, effectClient.get(), priority, sessionId, io);
if (pDesc == NULL) {
@@ -5599,14 +5539,7 @@
}
}
- wclient = mClients.valueFor(pid);
-
- if (wclient != NULL) {
- client = wclient.promote();
- } else {
- client = new Client(this, pid);
- mClients.add(pid, client);
- }
+ sp<Client> client = registerPid_l(pid);
// create effect on selected output thread
handle = thread->createEffect_l(client, effectClient, priority, sessionId,
@@ -5623,7 +5556,8 @@
return handle;
}
-status_t AudioFlinger::moveEffects(int sessionId, int srcOutput, int dstOutput)
+status_t AudioFlinger::moveEffects(int sessionId, audio_io_handle_t srcOutput,
+ audio_io_handle_t dstOutput)
{
ALOGV("moveEffects() session %d, srcOutput %d, dstOutput %d",
sessionId, srcOutput, dstOutput);
@@ -5674,7 +5608,7 @@
// transfer all effects one by one so that new effect chain is created on new thread with
// correct buffer sizes and audio parameters and effect engines reconfigured accordingly
- int dstOutput = dstThread->id();
+ audio_io_handle_t dstOutput = dstThread->id();
sp<EffectChain> dstChain;
uint32_t strategy = 0; // prevent compiler warning
sp<EffectModule> effect = chain->getEffectFromId_l(0);
@@ -5830,13 +5764,8 @@
sp<AudioFlinger::EffectModule> AudioFlinger::ThreadBase::getEffect_l(int sessionId, int effectId)
{
- sp<EffectModule> effect;
-
sp<EffectChain> chain = getEffectChain_l(sessionId);
- if (chain != 0) {
- effect = chain->getEffectFromId_l(effectId);
- }
- return effect;
+ return chain != 0 ? chain->getEffectFromId_l(effectId) : 0;
}
// PlaybackThread::addEffect_l() must be called with AudioFlinger::mLock and
@@ -5921,16 +5850,13 @@
sp<AudioFlinger::EffectChain> AudioFlinger::ThreadBase::getEffectChain_l(int sessionId)
{
- sp<EffectChain> chain;
-
size_t size = mEffectChains.size();
for (size_t i = 0; i < size; i++) {
if (mEffectChains[i]->sessionId() == sessionId) {
- chain = mEffectChains[i];
- break;
+ return mEffectChains[i];
}
}
- return chain;
+ return 0;
}
void AudioFlinger::ThreadBase::setMode(audio_mode_t mode)
@@ -5944,13 +5870,13 @@
void AudioFlinger::ThreadBase::disconnectEffect(const sp<EffectModule>& effect,
const wp<EffectHandle>& handle,
- bool unpiniflast) {
+ bool unpinIfLast) {
Mutex::Autolock _l(mLock);
ALOGV("disconnectEffect() %p effect %p", this, effect.get());
// delete the effect module if removing last handle on it
if (effect->removeHandle(handle) == 0) {
- if (!effect->isPinned() || unpiniflast) {
+ if (!effect->isPinned() || unpinIfLast) {
removeEffect_l(effect);
AudioSystem::unregisterEffect(effect->id());
}
@@ -6263,23 +6189,19 @@
sp<AudioFlinger::EffectHandle> AudioFlinger::EffectModule::controlHandle()
{
Mutex::Autolock _l(mLock);
- sp<EffectHandle> handle;
- if (mHandles.size() != 0) {
- handle = mHandles[0].promote();
- }
- return handle;
+ return mHandles.size() != 0 ? mHandles[0].promote() : 0;
}
-void AudioFlinger::EffectModule::disconnect(const wp<EffectHandle>& handle, bool unpiniflast)
+void AudioFlinger::EffectModule::disconnect(const wp<EffectHandle>& handle, bool unpinIfLast)
{
- ALOGV("disconnect() %p handle %p ", this, handle.unsafe_get());
+ ALOGV("disconnect() %p handle %p", this, handle.unsafe_get());
// keep a strong reference on this EffectModule to avoid calling the
// destructor before we exit
sp<EffectModule> keep(this);
{
sp<ThreadBase> thread = mThread.promote();
if (thread != 0) {
- thread->disconnectEffect(keep, handle, unpiniflast);
+ thread->disconnectEffect(keep, handle, unpinIfLast);
}
}
}
@@ -6622,7 +6544,7 @@
return NO_ERROR;
}
-bool AudioFlinger::EffectModule::isEnabled()
+bool AudioFlinger::EffectModule::isEnabled() const
{
switch (mState) {
case RESTART:
@@ -6638,7 +6560,7 @@
}
}
-bool AudioFlinger::EffectModule::isProcessEnabled()
+bool AudioFlinger::EffectModule::isProcessEnabled() const
{
switch (mState) {
case RESTART:
@@ -6951,13 +6873,13 @@
disconnect(true);
}
-void AudioFlinger::EffectHandle::disconnect(bool unpiniflast)
+void AudioFlinger::EffectHandle::disconnect(bool unpinIfLast)
{
- ALOGV("disconnect(%s)", unpiniflast ? "true" : "false");
+ ALOGV("disconnect(%s)", unpinIfLast ? "true" : "false");
if (mEffect == 0) {
return;
}
- mEffect->disconnect(this, unpiniflast);
+ mEffect->disconnect(this, unpinIfLast);
if (mHasControl && mEnabled) {
sp<ThreadBase> thread = mEffect->thread().promote();
@@ -6970,9 +6892,11 @@
mEffect.clear();
if (mClient != 0) {
if (mCblk != NULL) {
+ // unlike ~TrackBase(), mCblk is never a local new, so don't delete
mCblk->~effect_param_cblk_t(); // destroy our shared-structure.
}
- mCblkMemory.clear(); // and free the shared memory
+ mCblkMemory.clear(); // free the shared memory before releasing the heap it belongs to
+ // Client destructor must run with AudioFlinger mutex locked
Mutex::Autolock _l(mClient->audioFlinger()->mLock);
mClient.clear();
}
@@ -7054,10 +6978,6 @@
return mEffect->command(cmdCode, cmdSize, pCmdData, replySize, pReplyData);
}
-sp<IMemory> AudioFlinger::EffectHandle::getCblk() const {
- return mCblkMemory;
-}
-
void AudioFlinger::EffectHandle::setControl(bool hasControl, bool signal, bool enabled)
{
ALOGV("setControl %p control %d", this, hasControl);
@@ -7102,7 +7022,7 @@
bool locked = mCblk != NULL && tryLock(mCblk->lock);
snprintf(buffer, size, "\t\t\t%05d %05d %01u %01u %05u %05u\n",
- (mClient == NULL) ? getpid() : mClient->pid(),
+ (mClient == 0) ? getpid() : mClient->pid(),
mPriority,
mHasControl,
!locked,
@@ -7144,48 +7064,42 @@
// getEffectFromDesc_l() must be called with ThreadBase::mLock held
sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromDesc_l(effect_descriptor_t *descriptor)
{
- sp<EffectModule> effect;
size_t size = mEffects.size();
for (size_t i = 0; i < size; i++) {
if (memcmp(&mEffects[i]->desc().uuid, &descriptor->uuid, sizeof(effect_uuid_t)) == 0) {
- effect = mEffects[i];
- break;
+ return mEffects[i];
}
}
- return effect;
+ return 0;
}
// getEffectFromId_l() must be called with ThreadBase::mLock held
sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromId_l(int id)
{
- sp<EffectModule> effect;
size_t size = mEffects.size();
for (size_t i = 0; i < size; i++) {
// by convention, return first effect if id provided is 0 (0 is never a valid id)
if (id == 0 || mEffects[i]->id() == id) {
- effect = mEffects[i];
- break;
+ return mEffects[i];
}
}
- return effect;
+ return 0;
}
// getEffectFromType_l() must be called with ThreadBase::mLock held
sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromType_l(
const effect_uuid_t *type)
{
- sp<EffectModule> effect;
size_t size = mEffects.size();
for (size_t i = 0; i < size; i++) {
if (memcmp(&mEffects[i]->desc().type, type, sizeof(effect_uuid_t)) == 0) {
- effect = mEffects[i];
- break;
+ return mEffects[i];
}
}
- return effect;
+ return 0;
}
// Must be called with EffectChain::mLock locked
@@ -7626,12 +7540,8 @@
sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectIfEnabled(
const effect_uuid_t *type)
{
- sp<EffectModule> effect;
- effect = getEffectFromType_l(type);
- if (effect != 0 && !effect->isEnabled()) {
- effect.clear();
- }
- return effect;
+ sp<EffectModule> effect = getEffectFromType_l(type);
+ return effect != 0 && effect->isEnabled() ? effect : 0;
}
void AudioFlinger::EffectChain::checkSuspendOnEffectEnabled(const sp<EffectModule>& effect,
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 3f3188c..fdcd916 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -67,7 +67,7 @@
virtual status_t dump(int fd, const Vector<String16>& args);
- // IAudioFlinger interface
+ // IAudioFlinger interface, in binder opcode order
virtual sp<IAudioTrack> createTrack(
pid_t pid,
audio_stream_type_t streamType,
@@ -77,117 +77,13 @@
int frameCount,
uint32_t flags,
const sp<IMemory>& sharedBuffer,
- int output,
+ audio_io_handle_t output,
int *sessionId,
status_t *status);
- virtual uint32_t sampleRate(int output) const;
- virtual int channelCount(int output) const;
- virtual audio_format_t format(int output) const;
- virtual size_t frameCount(int output) const;
- virtual uint32_t latency(int output) const;
-
- virtual status_t setMasterVolume(float value);
- virtual status_t setMasterMute(bool muted);
-
- virtual float masterVolume() const;
- virtual bool masterMute() const;
-
- virtual status_t setStreamVolume(audio_stream_type_t stream, float value, int output);
- virtual status_t setStreamMute(audio_stream_type_t stream, bool muted);
-
- virtual float streamVolume(audio_stream_type_t stream, int output) const;
- virtual bool streamMute(audio_stream_type_t stream) const;
-
- virtual status_t setMode(audio_mode_t mode);
-
- virtual status_t setMicMute(bool state);
- virtual bool getMicMute() const;
-
- virtual status_t setParameters(int ioHandle, const String8& keyValuePairs);
- virtual String8 getParameters(int ioHandle, const String8& keys);
-
- virtual void registerClient(const sp<IAudioFlingerClient>& client);
-
- virtual size_t getInputBufferSize(uint32_t sampleRate, audio_format_t format, int channelCount);
- virtual unsigned int getInputFramesLost(int ioHandle);
-
- virtual int openOutput(uint32_t *pDevices,
- uint32_t *pSamplingRate,
- audio_format_t *pFormat,
- uint32_t *pChannels,
- uint32_t *pLatencyMs,
- uint32_t flags);
-
- virtual int openDuplicateOutput(int output1, int output2);
-
- virtual status_t closeOutput(int output);
-
- virtual status_t suspendOutput(int output);
-
- virtual status_t restoreOutput(int output);
-
- virtual int openInput(uint32_t *pDevices,
- uint32_t *pSamplingRate,
- audio_format_t *pFormat,
- uint32_t *pChannels,
- audio_in_acoustics_t acoustics);
-
- virtual status_t closeInput(int input);
-
- virtual status_t setStreamOutput(audio_stream_type_t stream, int output);
-
- virtual status_t setVoiceVolume(float volume);
-
- virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, int output);
-
- virtual int newAudioSessionId();
-
- virtual void acquireAudioSessionId(int audioSession);
-
- virtual void releaseAudioSessionId(int audioSession);
-
- virtual status_t queryNumberEffects(uint32_t *numEffects);
-
- virtual status_t queryEffect(uint32_t index, effect_descriptor_t *descriptor);
-
- virtual status_t getEffectDescriptor(effect_uuid_t *pUuid, effect_descriptor_t *descriptor);
-
- virtual sp<IEffect> createEffect(pid_t pid,
- effect_descriptor_t *pDesc,
- const sp<IEffectClient>& effectClient,
- int32_t priority,
- int io,
- int sessionId,
- status_t *status,
- int *id,
- int *enabled);
-
- virtual status_t moveEffects(int sessionId, int srcOutput, int dstOutput);
-
- enum hardware_call_state {
- AUDIO_HW_IDLE = 0,
- AUDIO_HW_INIT,
- AUDIO_HW_OUTPUT_OPEN,
- AUDIO_HW_OUTPUT_CLOSE,
- AUDIO_HW_INPUT_OPEN,
- AUDIO_HW_INPUT_CLOSE,
- AUDIO_HW_STANDBY,
- AUDIO_HW_SET_MASTER_VOLUME,
- AUDIO_HW_GET_ROUTING,
- AUDIO_HW_SET_ROUTING,
- AUDIO_HW_GET_MODE,
- AUDIO_HW_SET_MODE,
- AUDIO_HW_GET_MIC_MUTE,
- AUDIO_HW_SET_MIC_MUTE,
- AUDIO_SET_VOICE_VOLUME,
- AUDIO_SET_PARAMETER,
- };
-
- // record interface
virtual sp<IAudioRecord> openRecord(
pid_t pid,
- int input,
+ audio_io_handle_t input,
uint32_t sampleRate,
audio_format_t format,
uint32_t channelMask,
@@ -196,22 +92,116 @@
int *sessionId,
status_t *status);
+ virtual uint32_t sampleRate(audio_io_handle_t output) const;
+ virtual int channelCount(audio_io_handle_t output) const;
+ virtual audio_format_t format(audio_io_handle_t output) const;
+ virtual size_t frameCount(audio_io_handle_t output) const;
+ virtual uint32_t latency(audio_io_handle_t output) const;
+
+ virtual status_t setMasterVolume(float value);
+ virtual status_t setMasterMute(bool muted);
+
+ virtual float masterVolume() const;
+ virtual bool masterMute() const;
+
+ virtual status_t setStreamVolume(audio_stream_type_t stream, float value,
+ audio_io_handle_t output);
+ virtual status_t setStreamMute(audio_stream_type_t stream, bool muted);
+
+ virtual float streamVolume(audio_stream_type_t stream,
+ audio_io_handle_t output) const;
+ virtual bool streamMute(audio_stream_type_t stream) const;
+
+ virtual status_t setMode(audio_mode_t mode);
+
+ virtual status_t setMicMute(bool state);
+ virtual bool getMicMute() const;
+
+ virtual status_t setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs);
+ virtual String8 getParameters(audio_io_handle_t ioHandle, const String8& keys) const;
+
+ virtual void registerClient(const sp<IAudioFlingerClient>& client);
+
+ virtual size_t getInputBufferSize(uint32_t sampleRate, audio_format_t format, int channelCount) const;
+
+ virtual audio_io_handle_t openOutput(uint32_t *pDevices,
+ uint32_t *pSamplingRate,
+ audio_format_t *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pLatencyMs,
+ uint32_t flags);
+
+ virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1,
+ audio_io_handle_t output2);
+
+ virtual status_t closeOutput(audio_io_handle_t output);
+
+ virtual status_t suspendOutput(audio_io_handle_t output);
+
+ virtual status_t restoreOutput(audio_io_handle_t output);
+
+ virtual audio_io_handle_t openInput(uint32_t *pDevices,
+ uint32_t *pSamplingRate,
+ audio_format_t *pFormat,
+ uint32_t *pChannels,
+ audio_in_acoustics_t acoustics);
+
+ virtual status_t closeInput(audio_io_handle_t input);
+
+ virtual status_t setStreamOutput(audio_stream_type_t stream, audio_io_handle_t output);
+
+ virtual status_t setVoiceVolume(float volume);
+
+ virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames,
+ audio_io_handle_t output) const;
+
+ virtual unsigned int getInputFramesLost(audio_io_handle_t ioHandle) const;
+
+ virtual int newAudioSessionId();
+
+ virtual void acquireAudioSessionId(int audioSession);
+
+ virtual void releaseAudioSessionId(int audioSession);
+
+ virtual status_t queryNumberEffects(uint32_t *numEffects) const;
+
+ virtual status_t queryEffect(uint32_t index, effect_descriptor_t *descriptor) const;
+
+ virtual status_t getEffectDescriptor(const effect_uuid_t *pUuid,
+ effect_descriptor_t *descriptor) const;
+
+ virtual sp<IEffect> createEffect(pid_t pid,
+ effect_descriptor_t *pDesc,
+ const sp<IEffectClient>& effectClient,
+ int32_t priority,
+ audio_io_handle_t io,
+ int sessionId,
+ status_t *status,
+ int *id,
+ int *enabled);
+
+ virtual status_t moveEffects(int sessionId, audio_io_handle_t srcOutput,
+ audio_io_handle_t dstOutput);
+
virtual status_t onTransact(
uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags);
- audio_mode_t getMode() const { return mMode; }
-
- bool btNrecIsOff() { return mBtNrecIsOff; }
+ // end of IAudioFlinger interface
private:
+ audio_mode_t getMode() const { return mMode; }
+
+ bool btNrecIsOff() const { return mBtNrecIsOff; }
AudioFlinger();
virtual ~AudioFlinger();
- status_t initCheck() const;
+ // call in any IAudioFlinger method that accesses mPrimaryHardwareDev
+ status_t initCheck() const { return mPrimaryHardwareDev == NULL ? NO_INIT : NO_ERROR; }
+
virtual void onFirstRef();
audio_hw_device_t* findSuitableHwDev_l(uint32_t devices);
void purgeStaleEffects_l();
@@ -228,7 +218,7 @@
virtual ~Client();
sp<MemoryDealer> heap() const;
pid_t pid() const { return mPid; }
- sp<AudioFlinger> audioFlinger() { return mAudioFlinger; }
+ sp<AudioFlinger> audioFlinger() const { return mAudioFlinger; }
private:
Client(const Client&);
@@ -285,7 +275,7 @@
RECORD // Thread class is RecordThread
};
- ThreadBase (const sp<AudioFlinger>& audioFlinger, int id, uint32_t device, type_t type);
+ ThreadBase (const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id, uint32_t device, type_t type);
virtual ~ThreadBase();
status_t dumpBase(int fd, const Vector<String16>& args);
@@ -322,13 +312,13 @@
uint32_t flags,
const sp<IMemory>& sharedBuffer,
int sessionId);
- ~TrackBase();
+ virtual ~TrackBase();
virtual status_t start() = 0;
virtual void stop() = 0;
- sp<IMemory> getCblk() const;
+ sp<IMemory> getCblk() const { return mCblkMemory; }
audio_track_cblk_t* cblk() const { return mCblk; }
- int sessionId() { return mSessionId; }
+ int sessionId() const { return mSessionId; }
protected:
friend class ThreadBase;
@@ -348,11 +338,11 @@
return mFormat;
}
- int channelCount() const ;
+ int channelCount() const { return mChannelCount; }
- uint32_t channelMask() const;
+ uint32_t channelMask() const { return mChannelMask; }
- int sampleRate() const;
+ int sampleRate() const; // FIXME inline after cblk sr moved
void* getBuffer(uint32_t offset, uint32_t frames) const;
@@ -376,7 +366,6 @@
uint32_t mFrameCount;
// we don't really need a lock for these
track_state mState;
- int mClientTid;
const audio_format_t mFormat;
uint32_t mFlags;
const int mSessionId;
@@ -409,11 +398,13 @@
virtual status_t initCheck() const = 0;
type_t type() const { return mType; }
- uint32_t sampleRate() const;
- int channelCount() const;
- audio_format_t format() const;
- size_t frameCount() const;
+ uint32_t sampleRate() const { return mSampleRate; }
+ int channelCount() const { return mChannelCount; }
+ audio_format_t format() const { return mFormat; }
+ size_t frameCount() const { return mFrameCount; }
void wakeUp() { mWaitWorkCV.broadcast(); }
+ // Should be "virtual status_t requestExitAndWait()" and override same
+ // method in Thread, but Thread::requestExitAndWait() is not yet virtual.
void exit();
virtual bool checkForNewParameters_l() = 0;
virtual status_t setParameters(const String8& keyValuePairs);
@@ -422,7 +413,7 @@
void sendConfigEvent(int event, int param = 0);
void sendConfigEvent_l(int event, int param = 0);
void processConfigEvents();
- int id() const { return mId;}
+ audio_io_handle_t id() const { return mId;}
bool standby() { return mStandby; }
uint32_t device() { return mDevice; }
virtual audio_stream_t* stream() = 0;
@@ -437,7 +428,7 @@
status_t *status);
void disconnectEffect(const sp< EffectModule>& effect,
const wp<EffectHandle>& handle,
- bool unpiniflast);
+ bool unpinIfLast);
// return values for hasAudioSession (bit field)
enum effect_state {
@@ -544,8 +535,7 @@
status_t mParamStatus;
Vector<ConfigEvent> mConfigEvents;
bool mStandby;
- int mId;
- bool mExiting;
+ const audio_io_handle_t mId;
Vector< sp<EffectChain> > mEffectChains;
uint32_t mDevice; // output device for PlaybackThread
// input + output devices for RecordThread
@@ -559,6 +549,18 @@
KeyedVector< int, KeyedVector< int, sp<SuspendedSessionDesc> > > mSuspendedSessions;
};
+ struct stream_type_t {
+ stream_type_t()
+ : volume(1.0f),
+ mute(false),
+ valid(true)
+ {
+ }
+ float volume;
+ bool mute;
+ bool valid;
+ };
+
// --- PlaybackThread ---
class PlaybackThread : public ThreadBase {
public:
@@ -581,7 +583,7 @@
int frameCount,
const sp<IMemory>& sharedBuffer,
int sessionId);
- ~Track();
+ virtual ~Track();
void dump(char* buffer, size_t size);
virtual status_t start();
@@ -595,15 +597,15 @@
return mName;
}
- audio_stream_type_t type() const {
+ audio_stream_type_t streamType() const {
return mStreamType;
}
status_t attachAuxEffect(int EffectId);
void setAuxBuffer(int EffectId, int32_t *buffer);
- int32_t *auxBuffer() { return mAuxBuffer; }
+ int32_t *auxBuffer() const { return mAuxBuffer; }
void setMainBuffer(int16_t *buffer) { mMainBuffer = buffer; }
- int16_t *mainBuffer() { return mMainBuffer; }
- int auxEffectId() { return mAuxEffectId; }
+ int16_t *mainBuffer() const { return mMainBuffer; }
+ int auxEffectId() const { return mAuxEffectId; }
protected:
@@ -617,7 +619,7 @@
Track& operator = (const Track&);
virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
- bool isMuted() { return mMute; }
+ bool isMuted() const { return mMute; }
bool isPausing() const {
return mState == PAUSING;
}
@@ -664,14 +666,14 @@
audio_format_t format,
uint32_t channelMask,
int frameCount);
- ~OutputTrack();
+ virtual ~OutputTrack();
virtual status_t start();
virtual void stop();
bool write(int16_t* data, uint32_t frames);
- bool bufferQueueEmpty() { return (mBufferQueue.size() == 0) ? true : false; }
- bool isActive() { return mActive; }
- const wp<ThreadBase>& thread() { return mThread; }
+ bool bufferQueueEmpty() const { return (mBufferQueue.size() == 0) ? true : false; }
+ bool isActive() const { return mActive; }
+ const wp<ThreadBase>& thread() const { return mThread; }
private:
@@ -691,8 +693,8 @@
DuplicatingThread* const mSourceThread; // for waitTimeMs() in write()
}; // end of OutputTrack
- PlaybackThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id,
- uint32_t device, type_t type);
+ PlaybackThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
+ audio_io_handle_t id, uint32_t device, type_t type);
virtual ~PlaybackThread();
virtual status_t dump(int fd, const Vector<String16>& args);
@@ -708,8 +710,8 @@
virtual status_t setMasterVolume(float value);
virtual status_t setMasterMute(bool muted);
- virtual float masterVolume() const;
- virtual bool masterMute() const;
+ virtual float masterVolume() const { return mMasterVolume; }
+ virtual bool masterMute() const { return mMasterMute; }
virtual status_t setStreamVolume(audio_stream_type_t stream, float value);
virtual status_t setStreamMute(audio_stream_type_t stream, bool muted);
@@ -738,7 +740,7 @@
virtual String8 getParameters(const String8& keys);
virtual void audioConfigChanged_l(int event, int param = 0);
virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames);
- int16_t *mixBuffer() { return mMixBuffer; };
+ int16_t *mixBuffer() const { return mMixBuffer; };
virtual void detachAuxEffect_l(int effectId);
status_t attachAuxEffect(const sp<AudioFlinger::PlaybackThread::Track> track,
@@ -753,18 +755,6 @@
void setStreamValid(audio_stream_type_t streamType, bool valid);
- struct stream_type_t {
- stream_type_t()
- : volume(1.0f),
- mute(false),
- valid(true)
- {
- }
- float volume;
- bool mute;
- bool valid;
- };
-
protected:
int16_t* mMixBuffer;
int mSuspended;
@@ -817,7 +807,7 @@
public:
MixerThread (const sp<AudioFlinger>& audioFlinger,
AudioStreamOut* output,
- int id,
+ audio_io_handle_t id,
uint32_t device,
type_t type = MIXER);
virtual ~MixerThread();
@@ -844,8 +834,9 @@
class DirectOutputThread : public PlaybackThread {
public:
- DirectOutputThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device);
- ~DirectOutputThread();
+ DirectOutputThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
+ audio_io_handle_t id, uint32_t device);
+ virtual ~DirectOutputThread();
// Thread virtuals
virtual bool threadLoop();
@@ -870,8 +861,9 @@
class DuplicatingThread : public MixerThread {
public:
- DuplicatingThread (const sp<AudioFlinger>& audioFlinger, MixerThread* mainThread, int id);
- ~DuplicatingThread();
+ DuplicatingThread (const sp<AudioFlinger>& audioFlinger, MixerThread* mainThread,
+ audio_io_handle_t id);
+ virtual ~DuplicatingThread();
// Thread virtuals
virtual bool threadLoop();
@@ -889,13 +881,16 @@
uint32_t mWaitTimeMs;
};
- PlaybackThread *checkPlaybackThread_l(int output) const;
- MixerThread *checkMixerThread_l(int output) const;
- RecordThread *checkRecordThread_l(int input) const;
- float streamVolumeInternal(audio_stream_type_t stream) const { return mStreamTypes[stream].volume; }
- void audioConfigChanged_l(int event, int ioHandle, void *param2);
+ PlaybackThread *checkPlaybackThread_l(audio_io_handle_t output) const;
+ MixerThread *checkMixerThread_l(audio_io_handle_t output) const;
+ RecordThread *checkRecordThread_l(audio_io_handle_t input) const;
+ float streamVolumeInternal(audio_stream_type_t stream) const
+ { return mStreamTypes[stream].volume; }
+ void audioConfigChanged_l(int event, audio_io_handle_t ioHandle, void *param2);
+ // allocate an audio_io_handle_t, session ID, or effect ID
uint32_t nextUniqueId();
+
status_t moveEffectChain_l(int sessionId,
AudioFlinger::PlaybackThread *srcThread,
AudioFlinger::PlaybackThread *dstThread,
@@ -946,7 +941,7 @@
int frameCount,
uint32_t flags,
int sessionId);
- ~RecordTrack();
+ virtual ~RecordTrack();
virtual status_t start();
virtual void stop();
@@ -973,9 +968,9 @@
AudioStreamIn *input,
uint32_t sampleRate,
uint32_t channels,
- int id,
+ audio_io_handle_t id,
uint32_t device);
- ~RecordThread();
+ virtual ~RecordThread();
virtual bool threadLoop();
virtual status_t readyToRun();
@@ -1064,7 +1059,7 @@
effect_descriptor_t *desc,
int id,
int sessionId);
- ~EffectModule();
+ virtual ~EffectModule();
enum effect_state {
IDLE,
@@ -1076,7 +1071,7 @@
DESTROYED
};
- int id() { return mId; }
+ int id() const { return mId; }
void process();
void updateState();
status_t command(uint32_t cmdCode,
@@ -1094,12 +1089,12 @@
uint32_t status() {
return mStatus;
}
- int sessionId() {
+ int sessionId() const {
return mSessionId;
}
status_t setEnabled(bool enabled);
- bool isEnabled();
- bool isProcessEnabled();
+ bool isEnabled() const;
+ bool isProcessEnabled() const;
void setInBuffer(int16_t *buffer) { mConfig.inputCfg.buffer.s16 = buffer; }
int16_t *inBuffer() { return mConfig.inputCfg.buffer.s16; }
@@ -1110,7 +1105,7 @@
const wp<ThreadBase>& thread() { return mThread; }
status_t addHandle(const sp<EffectHandle>& handle);
- void disconnect(const wp<EffectHandle>& handle, bool unpiniflast);
+ void disconnect(const wp<EffectHandle>& handle, bool unpinIfLast);
size_t removeHandle (const wp<EffectHandle>& handle);
effect_descriptor_t& desc() { return mDescriptor; }
@@ -1126,7 +1121,7 @@
sp<EffectHandle> controlHandle();
- bool isPinned() { return mPinned; }
+ bool isPinned() const { return mPinned; }
void unPin() { mPinned = false; }
status_t dump(int fd, const Vector<String16>& args);
@@ -1186,8 +1181,10 @@
uint32_t *replySize,
void *pReplyData);
virtual void disconnect();
- virtual void disconnect(bool unpiniflast);
- virtual sp<IMemory> getCblk() const;
+ private:
+ void disconnect(bool unpinIfLast);
+ public:
+ virtual sp<IMemory> getCblk() const { return mCblkMemory; }
virtual status_t onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags);
@@ -1203,13 +1200,13 @@
uint32_t replySize,
void *pReplyData);
void setEnabled(bool enabled);
- bool enabled() { return mEnabled; }
+ bool enabled() const { return mEnabled; }
// Getters
- int id() { return mEffect->id(); }
- int priority() { return mPriority; }
- bool hasControl() { return mHasControl; }
- sp<EffectModule> effect() { return mEffect; }
+ int id() const { return mEffect->id(); }
+ int priority() const { return mPriority; }
+ bool hasControl() const { return mHasControl; }
+ sp<EffectModule> effect() const { return mEffect; }
void dump(char* buffer, size_t size);
@@ -1221,7 +1218,7 @@
sp<EffectModule> mEffect; // pointer to controlled EffectModule
sp<IEffectClient> mEffectClient; // callback interface for client notifications
- sp<Client> mClient; // client for shared memory allocation
+ /*const*/ sp<Client> mClient; // client for shared memory allocation, see disconnect()
sp<IMemory> mCblkMemory; // shared memory for control block
effect_param_cblk_t* mCblk; // control block for deferred parameter setting via shared memory
uint8_t* mBuffer; // pointer to parameter area in shared memory
@@ -1241,7 +1238,7 @@
class EffectChain: public RefBase {
public:
EffectChain(const wp<ThreadBase>& wThread, int sessionId);
- ~EffectChain();
+ virtual ~EffectChain();
// special key used for an entry in mSuspendedEffects keyed vector
// corresponding to a suspend all request.
@@ -1263,7 +1260,7 @@
status_t addEffect_l(const sp<EffectModule>& handle);
size_t removeEffect_l(const sp<EffectModule>& handle);
- int sessionId() { return mSessionId; }
+ int sessionId() const { return mSessionId; }
void setSessionId(int sessionId) { mSessionId = sessionId; }
sp<EffectModule> getEffectFromDesc_l(effect_descriptor_t *descriptor);
@@ -1277,26 +1274,26 @@
mInBuffer = buffer;
mOwnInBuffer = ownsBuffer;
}
- int16_t *inBuffer() {
+ int16_t *inBuffer() const {
return mInBuffer;
}
void setOutBuffer(int16_t *buffer) {
mOutBuffer = buffer;
}
- int16_t *outBuffer() {
+ int16_t *outBuffer() const {
return mOutBuffer;
}
void incTrackCnt() { android_atomic_inc(&mTrackCnt); }
void decTrackCnt() { android_atomic_dec(&mTrackCnt); }
- int32_t trackCnt() { return mTrackCnt;}
+ int32_t trackCnt() const { return mTrackCnt;}
void incActiveTrackCnt() { android_atomic_inc(&mActiveTrackCnt);
mTailBufferCount = mMaxTailBuffers; }
void decActiveTrackCnt() { android_atomic_dec(&mActiveTrackCnt); }
- int32_t activeTrackCnt() { return mActiveTrackCnt;}
+ int32_t activeTrackCnt() const { return mActiveTrackCnt;}
- uint32_t strategy() { return mStrategy; }
+ uint32_t strategy() const { return mStrategy; }
void setStrategy(uint32_t strategy)
{ mStrategy = strategy; }
@@ -1393,22 +1390,45 @@
mutable Mutex mLock;
- DefaultKeyedVector< pid_t, wp<Client> > mClients;
+ DefaultKeyedVector< pid_t, wp<Client> > mClients; // see ~Client()
mutable Mutex mHardwareLock;
- audio_hw_device_t* mPrimaryHardwareDev;
+
+ // These two fields are immutable after onFirstRef(), so no lock needed to access
+ audio_hw_device_t* mPrimaryHardwareDev; // mAudioHwDevs[0] or NULL
Vector<audio_hw_device_t*> mAudioHwDevs;
+
+ enum hardware_call_state {
+ AUDIO_HW_IDLE = 0,
+ AUDIO_HW_INIT,
+ AUDIO_HW_OUTPUT_OPEN,
+ AUDIO_HW_OUTPUT_CLOSE,
+ AUDIO_HW_INPUT_OPEN,
+ AUDIO_HW_INPUT_CLOSE,
+ AUDIO_HW_STANDBY,
+ AUDIO_HW_SET_MASTER_VOLUME,
+ AUDIO_HW_GET_ROUTING,
+ AUDIO_HW_SET_ROUTING,
+ AUDIO_HW_GET_MODE,
+ AUDIO_HW_SET_MODE,
+ AUDIO_HW_GET_MIC_MUTE,
+ AUDIO_HW_SET_MIC_MUTE,
+ AUDIO_SET_VOICE_VOLUME,
+ AUDIO_SET_PARAMETER,
+ AUDIO_HW_GET_INPUT_BUFFER_SIZE,
+ };
+
mutable hardware_call_state mHardwareStatus; // for dump only
- DefaultKeyedVector< int, sp<PlaybackThread> > mPlaybackThreads;
- PlaybackThread::stream_type_t mStreamTypes[AUDIO_STREAM_CNT];
+ DefaultKeyedVector< audio_io_handle_t, sp<PlaybackThread> > mPlaybackThreads;
+ stream_type_t mStreamTypes[AUDIO_STREAM_CNT];
// both are protected by mLock
float mMasterVolume;
bool mMasterMute;
- DefaultKeyedVector< int, sp<RecordThread> > mRecordThreads;
+ DefaultKeyedVector< audio_io_handle_t, sp<RecordThread> > mRecordThreads;
DefaultKeyedVector< pid_t, sp<NotificationClient> > mNotificationClients;
volatile int32_t mNextUniqueId;
@@ -1419,6 +1439,10 @@
float masterVolume_l() const { return mMasterVolume; }
bool masterMute_l() const { return mMasterMute; }
+
+private:
+ sp<Client> registerPid_l(pid_t pid); // always returns non-0
+
};
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index 0b9f8bab..191520a 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -68,7 +68,7 @@
// t->prevAuxLevel
// t->frameCount
t->channelCount = 2;
- t->enabled = 0;
+ t->enabled = false;
t->format = 16;
t->channelMask = AUDIO_CHANNEL_OUT_STEREO;
t->bufferProvider = NULL;
@@ -121,8 +121,8 @@
assert(uint32_t(name) < MAX_NUM_TRACKS);
ALOGV("deleteTrackName(%d)", name);
track_t& track(mState.tracks[ name ]);
- if (track.enabled != 0) {
- track.enabled = 0;
+ if (track.enabled) {
+ track.enabled = false;
invalidateState(1<<name);
}
if (track.resampler != NULL) {
@@ -143,8 +143,8 @@
assert(uint32_t(name) < MAX_NUM_TRACKS);
track_t& track = mState.tracks[name];
- if (track.enabled != 1) {
- track.enabled = 1;
+ if (!track.enabled) {
+ track.enabled = true;
ALOGV("enable(%d)", name);
invalidateState(1 << name);
}
@@ -156,8 +156,8 @@
assert(uint32_t(name) < MAX_NUM_TRACKS);
track_t& track = mState.tracks[name];
- if (track.enabled != 0) {
- track.enabled = 0;
+ if (track.enabled) {
+ track.enabled = false;
ALOGV("disable(%d)", name);
invalidateState(1 << name);
}
@@ -296,18 +296,6 @@
return false;
}
-bool AudioMixer::track_t::doesResample() const
-{
- return resampler != NULL;
-}
-
-void AudioMixer::track_t::resetResampler()
-{
- if (resampler != NULL) {
- resampler->reset();
- }
-}
-
inline
void AudioMixer::track_t::adjustVolumeRamp(bool aux)
{
@@ -327,20 +315,11 @@
}
}
-size_t AudioMixer::track_t::getUnreleasedFrames()
-{
- if (resampler != NULL) {
- return resampler->getUnreleasedFrames();
- }
- return 0;
-}
-
-size_t AudioMixer::getUnreleasedFrames(int name)
+size_t AudioMixer::getUnreleasedFrames(int name) const
{
name -= TRACK0;
if (uint32_t(name) < MAX_NUM_TRACKS) {
- track_t& track(mState.tracks[name]);
- return track.getUnreleasedFrames();
+ return mState.tracks[name].getUnreleasedFrames();
}
return 0;
}
@@ -383,9 +362,9 @@
// compute everything we need...
int countActiveTracks = 0;
- int all16BitsStereoNoResample = 1;
- int resampling = 0;
- int volumeRamp = 0;
+ bool all16BitsStereoNoResample = true;
+ bool resampling = false;
+ bool volumeRamp = false;
uint32_t en = state->enabledTracks;
while (en) {
const int i = 31 - __builtin_clz(en);
@@ -402,7 +381,7 @@
}
if (t.volumeInc[0]|t.volumeInc[1]) {
- volumeRamp = 1;
+ volumeRamp = true;
} else if (!t.doesResample() && t.volumeRL == 0) {
n |= NEEDS_MUTE_ENABLED;
}
@@ -412,16 +391,16 @@
t.hook = track__nop;
} else {
if ((n & NEEDS_AUX__MASK) == NEEDS_AUX_ENABLED) {
- all16BitsStereoNoResample = 0;
+ all16BitsStereoNoResample = false;
}
if ((n & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) {
- all16BitsStereoNoResample = 0;
- resampling = 1;
+ all16BitsStereoNoResample = false;
+ resampling = true;
t.hook = track__genericResample;
} else {
if ((n & NEEDS_CHANNEL_COUNT__MASK) == NEEDS_CHANNEL_1){
t.hook = track__16BitsMono;
- all16BitsStereoNoResample = 0;
+ all16BitsStereoNoResample = false;
}
if ((n & NEEDS_CHANNEL_COUNT__MASK) == NEEDS_CHANNEL_2){
t.hook = track__16BitsStereo;
@@ -469,7 +448,7 @@
// Now that the volume ramp has been done, set optimal state and
// track hooks for subsequent mixer process
if (countActiveTracks) {
- int allMuted = 1;
+ bool allMuted = true;
uint32_t en = state->enabledTracks;
while (en) {
const int i = 31 - __builtin_clz(en);
@@ -480,7 +459,7 @@
t.needs |= NEEDS_MUTE_ENABLED;
t.hook = track__nop;
} else {
- allMuted = 0;
+ allMuted = false;
}
}
if (allMuted) {
diff --git a/services/audioflinger/AudioMixer.h b/services/audioflinger/AudioMixer.h
index 84f6330..c709686 100644
--- a/services/audioflinger/AudioMixer.h
+++ b/services/audioflinger/AudioMixer.h
@@ -33,7 +33,7 @@
public:
AudioMixer(size_t frameCount, uint32_t sampleRate);
- ~AudioMixer();
+ /*virtual*/ ~AudioMixer(); // non-virtual saves a v-table, restore if sub-classed
static const uint32_t MAX_NUM_TRACKS = 32;
static const uint32_t MAX_NUM_CHANNELS = 2;
@@ -83,7 +83,7 @@
uint32_t trackNames() const { return mTrackNames; }
- size_t getUnreleasedFrames(int name);
+ size_t getUnreleasedFrames(int name) const;
private:
@@ -153,10 +153,11 @@
int32_t* auxBuffer;
bool setResampler(uint32_t sampleRate, uint32_t devSampleRate);
- bool doesResample() const;
- void resetResampler();
+ bool doesResample() const { return resampler != NULL; }
+ void resetResampler() { if (resampler != NULL) resampler->reset(); }
void adjustVolumeRamp(bool aux);
- size_t getUnreleasedFrames();
+ size_t getUnreleasedFrames() const { return resampler != NULL ?
+ resampler->getUnreleasedFrames() : 0; };
};
// pad to 32-bytes to fill cache line
diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp
index 1dddbb3..f8b430e 100644
--- a/services/audioflinger/AudioPolicyService.cpp
+++ b/services/audioflinger/AudioPolicyService.cpp
@@ -542,7 +542,7 @@
}
void AudioPolicyService::binderDied(const wp<IBinder>& who) {
- ALOGW("binderDied() %p, tid %d, calling tid %d", who.unsafe_get(), gettid(),
+ ALOGW("binderDied() %p, tid %d, calling pid %d", who.unsafe_get(), gettid(),
IPCThreadState::self()->getCallingPid());
}
@@ -588,10 +588,10 @@
}
dumpInternals(fd);
- if (mAudioCommandThread != NULL) {
+ if (mAudioCommandThread != 0) {
mAudioCommandThread->dump(fd);
}
- if (mTonePlaybackThread != NULL) {
+ if (mTonePlaybackThread != 0) {
mTonePlaybackThread->dump(fd);
}
@@ -819,7 +819,7 @@
status_t AudioPolicyService::AudioCommandThread::volumeCommand(audio_stream_type_t stream,
float volume,
- int output,
+ audio_io_handle_t output,
int delayMs)
{
status_t status = NO_ERROR;
@@ -849,7 +849,7 @@
return status;
}
-status_t AudioPolicyService::AudioCommandThread::parametersCommand(int ioHandle,
+status_t AudioPolicyService::AudioCommandThread::parametersCommand(audio_io_handle_t ioHandle,
const char *keyValuePairs,
int delayMs)
{
@@ -1019,7 +1019,7 @@
const char *keyValuePairs,
int delayMs)
{
- mAudioCommandThread->parametersCommand((int)ioHandle, keyValuePairs,
+ mAudioCommandThread->parametersCommand(ioHandle, keyValuePairs,
delayMs);
}
@@ -1029,7 +1029,7 @@
int delayMs)
{
return (int)mAudioCommandThread->volumeCommand(stream, volume,
- (int)output, delayMs);
+ output, delayMs);
}
int AudioPolicyService::startTone(audio_policy_tone_t tone,
@@ -1362,7 +1362,7 @@
audio_policy_output_flags_t flags)
{
sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
- if (af == NULL) {
+ if (af == 0) {
ALOGW("%s: could not get AudioFlinger", __func__);
return 0;
}
@@ -1376,7 +1376,7 @@
audio_io_handle_t output2)
{
sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
- if (af == NULL) {
+ if (af == 0) {
ALOGW("%s: could not get AudioFlinger", __func__);
return 0;
}
@@ -1386,7 +1386,7 @@
static int aps_close_output(void *service, audio_io_handle_t output)
{
sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
- if (af == NULL)
+ if (af == 0)
return PERMISSION_DENIED;
return af->closeOutput(output);
@@ -1395,7 +1395,7 @@
static int aps_suspend_output(void *service, audio_io_handle_t output)
{
sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
- if (af == NULL) {
+ if (af == 0) {
ALOGW("%s: could not get AudioFlinger", __func__);
return PERMISSION_DENIED;
}
@@ -1406,7 +1406,7 @@
static int aps_restore_output(void *service, audio_io_handle_t output)
{
sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
- if (af == NULL) {
+ if (af == 0) {
ALOGW("%s: could not get AudioFlinger", __func__);
return PERMISSION_DENIED;
}
@@ -1422,7 +1422,7 @@
audio_in_acoustics_t acoustics)
{
sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
- if (af == NULL) {
+ if (af == 0) {
ALOGW("%s: could not get AudioFlinger", __func__);
return 0;
}
@@ -1434,7 +1434,7 @@
static int aps_close_input(void *service, audio_io_handle_t input)
{
sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
- if (af == NULL)
+ if (af == 0)
return PERMISSION_DENIED;
return af->closeInput(input);
@@ -1444,7 +1444,7 @@
audio_io_handle_t output)
{
sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
- if (af == NULL)
+ if (af == 0)
return PERMISSION_DENIED;
return af->setStreamOutput(stream, output);
@@ -1455,10 +1455,10 @@
audio_io_handle_t dst_output)
{
sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
- if (af == NULL)
+ if (af == 0)
return PERMISSION_DENIED;
- return af->moveEffects(session, (int)src_output, (int)dst_output);
+ return af->moveEffects(session, src_output, dst_output);
}
static char * aps_get_parameters(void *service, audio_io_handle_t io_handle,
diff --git a/services/audioflinger/AudioPolicyService.h b/services/audioflinger/AudioPolicyService.h
index 62219e5..fdaf576 100644
--- a/services/audioflinger/AudioPolicyService.h
+++ b/services/audioflinger/AudioPolicyService.h
@@ -174,8 +174,10 @@
void startToneCommand(ToneGenerator::tone_type type,
audio_stream_type_t stream);
void stopToneCommand();
- status_t volumeCommand(audio_stream_type_t stream, float volume, int output, int delayMs = 0);
- status_t parametersCommand(int ioHandle, const char *keyValuePairs, int delayMs = 0);
+ status_t volumeCommand(audio_stream_type_t stream, float volume,
+ audio_io_handle_t output, int delayMs = 0);
+ status_t parametersCommand(audio_io_handle_t ioHandle,
+ const char *keyValuePairs, int delayMs = 0);
status_t voiceVolumeCommand(float volume, int delayMs = 0);
void insertCommand_l(AudioCommand *command, int delayMs = 0);
@@ -207,12 +209,12 @@
public:
audio_stream_type_t mStream;
float mVolume;
- int mIO;
+ audio_io_handle_t mIO;
};
class ParametersData {
public:
- int mIO;
+ audio_io_handle_t mIO;
String8 mKeyValuePairs;
};
diff --git a/services/audioflinger/AudioResampler.cpp b/services/audioflinger/AudioResampler.cpp
index feacd96..9486b9c 100644
--- a/services/audioflinger/AudioResampler.cpp
+++ b/services/audioflinger/AudioResampler.cpp
@@ -23,8 +23,10 @@
#include <cutils/log.h>
#include <cutils/properties.h>
#include "AudioResampler.h"
+#if 0
#include "AudioResamplerSinc.h"
#include "AudioResamplerCubic.h"
+#endif
#ifdef __arm__
#include <machine/cpu-features.h>
@@ -99,6 +101,7 @@
ALOGV("Create linear Resampler");
resampler = new AudioResamplerOrder1(bitDepth, inChannelCount, sampleRate);
break;
+#if 0
case MED_QUALITY:
ALOGV("Create cubic Resampler");
resampler = new AudioResamplerCubic(bitDepth, inChannelCount, sampleRate);
@@ -107,6 +110,7 @@
ALOGV("Create sinc Resampler");
resampler = new AudioResamplerSinc(bitDepth, inChannelCount, sampleRate);
break;
+#endif
}
// initialize resampler
@@ -130,12 +134,6 @@
mVolume[0] = mVolume[1] = 0;
mBuffer.frameCount = 0;
- // save format for quick lookup
- if (inChannelCount == 1) {
- mFormat = MONO_16_BIT;
- } else {
- mFormat = STEREO_16_BIT;
- }
}
AudioResampler::~AudioResampler() {
@@ -190,7 +188,7 @@
size_t outputSampleCount = outFrameCount * 2;
size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
- // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d\n",
+ // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d",
// outFrameCount, inputIndex, phaseFraction, phaseIncrement);
while (outputIndex < outputSampleCount) {
@@ -203,7 +201,7 @@
goto resampleStereo16_exit;
}
- // ALOGE("New buffer fetched: %d frames\n", mBuffer.frameCount);
+ // ALOGE("New buffer fetched: %d frames", mBuffer.frameCount);
if (mBuffer.frameCount > inputIndex) break;
inputIndex -= mBuffer.frameCount;
@@ -217,7 +215,7 @@
// handle boundary case
while (inputIndex == 0) {
- // ALOGE("boundary case\n");
+ // ALOGE("boundary case");
out[outputIndex++] += vl * Interp(mX0L, in[0], phaseFraction);
out[outputIndex++] += vr * Interp(mX0R, in[1], phaseFraction);
Advance(&inputIndex, &phaseFraction, phaseIncrement);
@@ -226,7 +224,7 @@
}
// process input samples
- // ALOGE("general case\n");
+ // ALOGE("general case");
#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1
if (inputIndex + 2 < mBuffer.frameCount) {
@@ -248,7 +246,7 @@
Advance(&inputIndex, &phaseFraction, phaseIncrement);
}
- // ALOGE("loop done - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
+ // ALOGE("loop done - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex);
// if done with buffer, save samples
if (inputIndex >= mBuffer.frameCount) {
@@ -265,7 +263,7 @@
}
}
- // ALOGE("output buffer full - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
+ // ALOGE("output buffer full - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex);
resampleStereo16_exit:
// save state
@@ -286,7 +284,7 @@
size_t outputSampleCount = outFrameCount * 2;
size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
- // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d\n",
+ // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d",
// outFrameCount, inputIndex, phaseFraction, phaseIncrement);
while (outputIndex < outputSampleCount) {
// buffer is empty, fetch a new one
@@ -298,7 +296,7 @@
mPhaseFraction = phaseFraction;
goto resampleMono16_exit;
}
- // ALOGE("New buffer fetched: %d frames\n", mBuffer.frameCount);
+ // ALOGE("New buffer fetched: %d frames", mBuffer.frameCount);
if (mBuffer.frameCount > inputIndex) break;
inputIndex -= mBuffer.frameCount;
@@ -310,7 +308,7 @@
// handle boundary case
while (inputIndex == 0) {
- // ALOGE("boundary case\n");
+ // ALOGE("boundary case");
int32_t sample = Interp(mX0L, in[0], phaseFraction);
out[outputIndex++] += vl * sample;
out[outputIndex++] += vr * sample;
@@ -320,7 +318,7 @@
}
// process input samples
- // ALOGE("general case\n");
+ // ALOGE("general case");
#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1
if (inputIndex + 2 < mBuffer.frameCount) {
@@ -343,7 +341,7 @@
}
- // ALOGE("loop done - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
+ // ALOGE("loop done - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex);
// if done with buffer, save samples
if (inputIndex >= mBuffer.frameCount) {
@@ -359,7 +357,7 @@
}
}
- // ALOGE("output buffer full - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
+ // ALOGE("output buffer full - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex);
resampleMono16_exit:
// save state
diff --git a/services/audioflinger/AudioResampler.h b/services/audioflinger/AudioResampler.h
index ffa690a..c23016e 100644
--- a/services/audioflinger/AudioResampler.h
+++ b/services/audioflinger/AudioResampler.h
@@ -54,7 +54,7 @@
AudioBufferProvider* provider) = 0;
virtual void reset();
- virtual size_t getUnreleasedFrames() { return mInputIndex; }
+ virtual size_t getUnreleasedFrames() const { return mInputIndex; }
protected:
// number of bits for phase fraction - 30 bits allows nearly 2x downsampling
@@ -66,16 +66,15 @@
// multiplier to calculate fixed point phase increment
static const double kPhaseMultiplier = 1L << kNumPhaseBits;
- enum format {MONO_16_BIT, STEREO_16_BIT};
AudioResampler(int bitDepth, int inChannelCount, int32_t sampleRate);
// prevent copying
AudioResampler(const AudioResampler&);
AudioResampler& operator=(const AudioResampler&);
- int32_t mBitDepth;
- int32_t mChannelCount;
- int32_t mSampleRate;
+ const int32_t mBitDepth;
+ const int32_t mChannelCount;
+ const int32_t mSampleRate;
int32_t mInSampleRate;
AudioBufferProvider::Buffer mBuffer;
union {
@@ -83,7 +82,6 @@
uint32_t mVolumeRL;
};
int16_t mTargetVolume[2];
- format mFormat;
size_t mInputIndex;
int32_t mPhaseIncrement;
uint32_t mPhaseFraction;
diff --git a/services/audioflinger/AudioResamplerCubic.cpp b/services/audioflinger/AudioResamplerCubic.cpp
index 47205ba..c0e760e 100644
--- a/services/audioflinger/AudioResamplerCubic.cpp
+++ b/services/audioflinger/AudioResamplerCubic.cpp
@@ -99,7 +99,7 @@
if (mBuffer.raw == NULL)
goto save_state; // ugly, but efficient
in = mBuffer.i16;
- // ALOGW("New buffer: offset=%p, frames=%d\n", mBuffer.raw, mBuffer.frameCount);
+ // ALOGW("New buffer: offset=%p, frames=%d", mBuffer.raw, mBuffer.frameCount);
}
// advance sample state
@@ -133,7 +133,7 @@
provider->getNextBuffer(&mBuffer);
if (mBuffer.raw == NULL)
return;
- // ALOGW("New buffer: offset=%p, frames=%d\n", mBuffer.raw, mBuffer.frameCount);
+ // ALOGW("New buffer: offset=%p, frames=%d", mBuffer.raw, mBuffer.frameCount);
}
int16_t *in = mBuffer.i16;
diff --git a/services/audioflinger/AudioResamplerSinc.cpp b/services/audioflinger/AudioResamplerSinc.cpp
index d012433..7a27b81 100644
--- a/services/audioflinger/AudioResamplerSinc.cpp
+++ b/services/audioflinger/AudioResamplerSinc.cpp
@@ -199,33 +199,32 @@
size_t outputSampleCount = outFrameCount * 2;
size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
- AudioBufferProvider::Buffer& buffer(mBuffer);
while (outputIndex < outputSampleCount) {
// buffer is empty, fetch a new one
- while (buffer.frameCount == 0) {
- buffer.frameCount = inFrameCount;
- provider->getNextBuffer(&buffer);
- if (buffer.raw == NULL) {
+ while (mBuffer.frameCount == 0) {
+ mBuffer.frameCount = inFrameCount;
+ provider->getNextBuffer(&mBuffer);
+ if (mBuffer.raw == NULL) {
goto resample_exit;
}
const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits;
if (phaseIndex == 1) {
// read one frame
- read<CHANNELS>(impulse, phaseFraction, buffer.i16, inputIndex);
+ read<CHANNELS>(impulse, phaseFraction, mBuffer.i16, inputIndex);
} else if (phaseIndex == 2) {
// read 2 frames
- read<CHANNELS>(impulse, phaseFraction, buffer.i16, inputIndex);
+ read<CHANNELS>(impulse, phaseFraction, mBuffer.i16, inputIndex);
inputIndex++;
if (inputIndex >= mBuffer.frameCount) {
inputIndex -= mBuffer.frameCount;
- provider->releaseBuffer(&buffer);
+ provider->releaseBuffer(&mBuffer);
} else {
- read<CHANNELS>(impulse, phaseFraction, buffer.i16, inputIndex);
+ read<CHANNELS>(impulse, phaseFraction, mBuffer.i16, inputIndex);
}
}
}
- int16_t *in = buffer.i16;
- const size_t frameCount = buffer.frameCount;
+ int16_t *in = mBuffer.i16;
+ const size_t frameCount = mBuffer.frameCount;
// Always read-in the first samples from the input buffer
int16_t* head = impulse + halfNumCoefs*CHANNELS;
@@ -264,7 +263,7 @@
// if done with buffer, save samples
if (inputIndex >= frameCount) {
inputIndex -= frameCount;
- provider->releaseBuffer(&buffer);
+ provider->releaseBuffer(&mBuffer);
}
}
diff --git a/services/audioflinger/AudioResamplerSinc.h b/services/audioflinger/AudioResamplerSinc.h
index 0e1bc44..f0a07b8 100644
--- a/services/audioflinger/AudioResamplerSinc.h
+++ b/services/audioflinger/AudioResamplerSinc.h
@@ -31,7 +31,7 @@
public:
AudioResamplerSinc(int bitDepth, int inChannelCount, int32_t sampleRate);
- ~AudioResamplerSinc();
+ virtual ~AudioResamplerSinc();
virtual void resample(int32_t* out, size_t outFrameCount,
AudioBufferProvider* provider);
diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/AppWidgetServiceImpl.java
index 250386f..41ede2e 100644
--- a/services/java/com/android/server/AppWidgetServiceImpl.java
+++ b/services/java/com/android/server/AppWidgetServiceImpl.java
@@ -573,12 +573,13 @@
mBoundRemoteViewsServices.remove(key);
}
+ int userId = UserId.getUserId(id.provider.uid);
// Bind to the RemoteViewsService (which will trigger a callback to the
// RemoteViewsAdapter.onServiceConnected())
final long token = Binder.clearCallingIdentity();
try {
conn = new ServiceConnectionProxy(key, connection);
- mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE);
+ mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE, userId);
mBoundRemoteViewsServices.put(key, conn);
} finally {
Binder.restoreCallingIdentity(token);
@@ -638,11 +639,11 @@
// Check if we need to destroy any services (if no other app widgets are
// referencing the same service)
- decrementAppWidgetServiceRefCount(appWidgetId);
+ decrementAppWidgetServiceRefCount(id);
}
// Destroys the cached factory on the RemoteViewsService's side related to the specified intent
- private void destroyRemoteViewsService(final Intent intent) {
+ private void destroyRemoteViewsService(final Intent intent, AppWidgetId id) {
final ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
@@ -663,11 +664,12 @@
}
};
+ int userId = UserId.getUserId(id.provider.uid);
// Bind to the service and remove the static intent->factory mapping in the
// RemoteViewsService.
final long token = Binder.clearCallingIdentity();
try {
- mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE);
+ mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE, userId);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -687,16 +689,16 @@
// Subtracts from the ref-count for a given RemoteViewsService intent, prompting a delete if
// the ref-count reaches zero.
- private void decrementAppWidgetServiceRefCount(int appWidgetId) {
+ private void decrementAppWidgetServiceRefCount(AppWidgetId id) {
Iterator<FilterComparison> it = mRemoteViewsServicesAppWidgets.keySet().iterator();
while (it.hasNext()) {
final FilterComparison key = it.next();
final HashSet<Integer> ids = mRemoteViewsServicesAppWidgets.get(key);
- if (ids.remove(appWidgetId)) {
+ if (ids.remove(id.appWidgetId)) {
// If we have removed the last app widget referencing this service, then we
// should destroy it and remove it from this set
if (ids.isEmpty()) {
- destroyRemoteViewsService(key.getIntent());
+ destroyRemoteViewsService(key.getIntent(), id);
it.remove();
}
}
@@ -888,10 +890,11 @@
}
};
+ int userId = UserId.getUserId(id.provider.uid);
// Bind to the service and call onDataSetChanged()
final long token = Binder.clearCallingIdentity();
try {
- mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE);
+ mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE, userId);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -1343,7 +1346,6 @@
void readStateFromFileLocked(FileInputStream stream) {
boolean success = false;
-
try {
XmlPullParser parser = Xml.newPullParser();
parser.setInput(stream, null);
@@ -1475,7 +1477,7 @@
}
AtomicFile savedStateFile() {
- int userId = Binder.getOrigCallingUser();
+ int userId = UserId.getCallingUserId();
File dir = new File("/data/system/users/" + userId);
File settingsFile = new File(dir, SETTINGS_FILENAME);
if (!dir.exists()) {
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index aba1bc6..86669f8 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -101,6 +101,7 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
@@ -154,6 +155,7 @@
final IWindowManager mIWindowManager;
final HandlerCaller mCaller;
private final InputMethodFileManager mFileManager;
+ private final InputMethodAndSubtypeListManager mImListManager;
final InputBindResult mNoBinding = new InputBindResult(null, null, -1);
@@ -555,6 +557,7 @@
synchronized (mMethodMap) {
mFileManager = new InputMethodFileManager(mMethodMap);
}
+ mImListManager = new InputMethodAndSubtypeListManager(context, this);
(new MyPackageMonitor()).register(mContext, true);
@@ -1693,6 +1696,19 @@
}
@Override
+ public boolean switchToNextInputMethod(IBinder token, boolean onlyCurrentIme) {
+ synchronized (mMethodMap) {
+ final ImeSubtypeListItem nextSubtype = mImListManager.getNextInputMethod(
+ onlyCurrentIme, mMethodMap.get(mCurMethodId), mCurrentSubtype);
+ if (nextSubtype == null) {
+ return false;
+ }
+ setInputMethodWithSubtypeId(token, nextSubtype.mImi.getId(), nextSubtype.mSubtypeId);
+ return true;
+ }
+ }
+
+ @Override
public InputMethodSubtype getLastInputMethodSubtype() {
synchronized (mMethodMap) {
final Pair<String, String> lastIme = mSettings.getLastInputMethodAndSubtypeLocked();
@@ -2109,62 +2125,9 @@
hideInputMethodMenuLocked();
- final TreeMap<InputMethodInfo, List<InputMethodSubtype>> sortedImmis =
- new TreeMap<InputMethodInfo, List<InputMethodSubtype>>(
- new Comparator<InputMethodInfo>() {
- @Override
- public int compare(InputMethodInfo imi1, InputMethodInfo imi2) {
- if (imi2 == null) return 0;
- if (imi1 == null) return 1;
- if (pm == null) {
- return imi1.getId().compareTo(imi2.getId());
- }
- CharSequence imiId1 = imi1.loadLabel(pm) + "/" + imi1.getId();
- CharSequence imiId2 = imi2.loadLabel(pm) + "/" + imi2.getId();
- return imiId1.toString().compareTo(imiId2.toString());
- }
- });
-
- sortedImmis.putAll(immis);
-
- final ArrayList<ImeSubtypeListItem> imList = new ArrayList<ImeSubtypeListItem>();
-
- for (InputMethodInfo imi : sortedImmis.keySet()) {
- if (imi == null) continue;
- List<InputMethodSubtype> explicitlyOrImplicitlyEnabledSubtypeList = immis.get(imi);
- HashSet<String> enabledSubtypeSet = new HashSet<String>();
- for (InputMethodSubtype subtype: explicitlyOrImplicitlyEnabledSubtypeList) {
- enabledSubtypeSet.add(String.valueOf(subtype.hashCode()));
- }
- ArrayList<InputMethodSubtype> subtypes = getSubtypes(imi);
- final CharSequence imeLabel = imi.loadLabel(pm);
- if (showSubtypes && enabledSubtypeSet.size() > 0) {
- final int subtypeCount = imi.getSubtypeCount();
- if (DEBUG) {
- Slog.v(TAG, "Add subtypes: " + subtypeCount + ", " + imi.getId());
- }
- for (int j = 0; j < subtypeCount; ++j) {
- final InputMethodSubtype subtype = imi.getSubtypeAt(j);
- final String subtypeHashCode = String.valueOf(subtype.hashCode());
- // We show all enabled IMEs and subtypes when an IME is shown.
- if (enabledSubtypeSet.contains(subtypeHashCode)
- && ((mInputShown && !isScreenLocked) || !subtype.isAuxiliary())) {
- final CharSequence subtypeLabel =
- subtype.overridesImplicitlyEnabledSubtype() ? null
- : subtype.getDisplayName(context, imi.getPackageName(),
- imi.getServiceInfo().applicationInfo);
- imList.add(new ImeSubtypeListItem(imeLabel, subtypeLabel, imi, j));
-
- // Removing this subtype from enabledSubtypeSet because we no longer
- // need to add an entry of this subtype to imList to avoid duplicated
- // entries.
- enabledSubtypeSet.remove(subtypeHashCode);
- }
- }
- } else {
- imList.add(new ImeSubtypeListItem(imeLabel, null, imi, NOT_A_SUBTYPE_ID));
- }
- }
+ final List<ImeSubtypeListItem> imList =
+ mImListManager.getSortedInputMethodAndSubtypeList(
+ showSubtypes, mInputShown, isScreenLocked);
if (lastInputMethodSubtypeId == NOT_A_SUBTYPE_ID) {
final InputMethodSubtype currentSubtype = getCurrentInputMethodSubtype();
@@ -2786,6 +2749,117 @@
}
}
+ private static class InputMethodAndSubtypeListManager {
+ private final Context mContext;
+ private final PackageManager mPm;
+ private final InputMethodManagerService mImms;
+ public InputMethodAndSubtypeListManager(Context context, InputMethodManagerService imms) {
+ mContext = context;
+ mPm = context.getPackageManager();
+ mImms = imms;
+ }
+
+ private final TreeMap<InputMethodInfo, List<InputMethodSubtype>> mSortedImmis =
+ new TreeMap<InputMethodInfo, List<InputMethodSubtype>>(
+ new Comparator<InputMethodInfo>() {
+ @Override
+ public int compare(InputMethodInfo imi1, InputMethodInfo imi2) {
+ if (imi2 == null) return 0;
+ if (imi1 == null) return 1;
+ if (mPm == null) {
+ return imi1.getId().compareTo(imi2.getId());
+ }
+ CharSequence imiId1 = imi1.loadLabel(mPm) + "/" + imi1.getId();
+ CharSequence imiId2 = imi2.loadLabel(mPm) + "/" + imi2.getId();
+ return imiId1.toString().compareTo(imiId2.toString());
+ }
+ });
+
+ public ImeSubtypeListItem getNextInputMethod(
+ boolean onlyCurrentIme, InputMethodInfo imi, InputMethodSubtype subtype) {
+ if (imi == null) {
+ return null;
+ }
+ final List<ImeSubtypeListItem> imList = getSortedInputMethodAndSubtypeList();
+ if (imList.size() <= 1) {
+ return null;
+ }
+ final int N = imList.size();
+ final int currentSubtypeId = subtype != null
+ ? mImms.getSubtypeIdFromHashCode(imi, subtype.hashCode())
+ : NOT_A_SUBTYPE_ID;
+ for (int i = 0; i < N; ++i) {
+ final ImeSubtypeListItem isli = imList.get(i);
+ if (isli.mImi.equals(imi) && isli.mSubtypeId == currentSubtypeId) {
+ if (!onlyCurrentIme) {
+ return imList.get((i + 1) % N);
+ }
+ for (int j = 0; j < N - 1; ++j) {
+ final ImeSubtypeListItem candidate = imList.get((i + j + 1) % N);
+ if (candidate.mImi.equals(imi)) {
+ return candidate;
+ }
+ }
+ return null;
+ }
+ }
+ return null;
+ }
+
+ public List<ImeSubtypeListItem> getSortedInputMethodAndSubtypeList() {
+ return getSortedInputMethodAndSubtypeList(true, false, false);
+ }
+
+ public List<ImeSubtypeListItem> getSortedInputMethodAndSubtypeList(boolean showSubtypes,
+ boolean inputShown, boolean isScreenLocked) {
+ final ArrayList<ImeSubtypeListItem> imList = new ArrayList<ImeSubtypeListItem>();
+ final HashMap<InputMethodInfo, List<InputMethodSubtype>> immis =
+ mImms.getExplicitlyOrImplicitlyEnabledInputMethodsAndSubtypeListLocked();
+ if (immis == null || immis.size() == 0) {
+ return Collections.emptyList();
+ }
+ mSortedImmis.clear();
+ mSortedImmis.putAll(immis);
+ for (InputMethodInfo imi : mSortedImmis.keySet()) {
+ if (imi == null) continue;
+ List<InputMethodSubtype> explicitlyOrImplicitlyEnabledSubtypeList = immis.get(imi);
+ HashSet<String> enabledSubtypeSet = new HashSet<String>();
+ for (InputMethodSubtype subtype: explicitlyOrImplicitlyEnabledSubtypeList) {
+ enabledSubtypeSet.add(String.valueOf(subtype.hashCode()));
+ }
+ ArrayList<InputMethodSubtype> subtypes = getSubtypes(imi);
+ final CharSequence imeLabel = imi.loadLabel(mPm);
+ if (showSubtypes && enabledSubtypeSet.size() > 0) {
+ final int subtypeCount = imi.getSubtypeCount();
+ if (DEBUG) {
+ Slog.v(TAG, "Add subtypes: " + subtypeCount + ", " + imi.getId());
+ }
+ for (int j = 0; j < subtypeCount; ++j) {
+ final InputMethodSubtype subtype = imi.getSubtypeAt(j);
+ final String subtypeHashCode = String.valueOf(subtype.hashCode());
+ // We show all enabled IMEs and subtypes when an IME is shown.
+ if (enabledSubtypeSet.contains(subtypeHashCode)
+ && ((inputShown && !isScreenLocked) || !subtype.isAuxiliary())) {
+ final CharSequence subtypeLabel =
+ subtype.overridesImplicitlyEnabledSubtype() ? null
+ : subtype.getDisplayName(mContext, imi.getPackageName(),
+ imi.getServiceInfo().applicationInfo);
+ imList.add(new ImeSubtypeListItem(imeLabel, subtypeLabel, imi, j));
+
+ // Removing this subtype from enabledSubtypeSet because we no longer
+ // need to add an entry of this subtype to imList to avoid duplicated
+ // entries.
+ enabledSubtypeSet.remove(subtypeHashCode);
+ }
+ }
+ } else {
+ imList.add(new ImeSubtypeListItem(imeLabel, null, imi, NOT_A_SUBTYPE_ID));
+ }
+ }
+ return imList;
+ }
+ }
+
/**
* Utility class for putting and getting settings for InputMethod
* TODO: Move all putters and getters of settings to this class.
diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java
index 5319432..308661f 100644
--- a/services/java/com/android/server/NativeDaemonConnector.java
+++ b/services/java/com/android/server/NativeDaemonConnector.java
@@ -34,8 +34,8 @@
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.LinkedList;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
/**
* Generic connector class for interfacing with a native daemon which uses the
@@ -50,15 +50,11 @@
private OutputStream mOutputStream;
private LocalLog mLocalLog;
- private final ResponseQueue mResponseQueue;
+ private final BlockingQueue<NativeDaemonEvent> mResponseQueue;
private INativeDaemonConnectorCallbacks mCallbacks;
private Handler mCallbackHandler;
- private AtomicInteger mSequenceNumber;
-
- private static final int DEFAULT_TIMEOUT = 1 * 60 * 1000; /* 1 minute */
-
/** Lock held whenever communicating with native daemon. */
private final Object mDaemonLock = new Object();
@@ -68,8 +64,7 @@
int responseQueueSize, String logTag, int maxLogSize) {
mCallbacks = callbacks;
mSocket = socket;
- mResponseQueue = new ResponseQueue(responseQueueSize);
- mSequenceNumber = new AtomicInteger(0);
+ mResponseQueue = new LinkedBlockingQueue<NativeDaemonEvent>(responseQueueSize);
TAG = logTag != null ? logTag : "NativeDaemonConnector";
mLocalLog = new LocalLog(maxLogSize);
}
@@ -84,7 +79,7 @@
try {
listenToSocket();
} catch (Exception e) {
- loge("Error in NativeDaemonConnector: " + e);
+ Slog.e(TAG, "Error in NativeDaemonConnector", e);
SystemClock.sleep(5000);
}
}
@@ -95,10 +90,12 @@
String event = (String) msg.obj;
try {
if (!mCallbacks.onEvent(msg.what, event, event.split(" "))) {
- log(String.format("Unhandled event '%s'", event));
+ Slog.w(TAG, String.format(
+ "Unhandled event '%s'", event));
}
} catch (Exception e) {
- loge("Error handling '" + event + "': " + e);
+ Slog.e(TAG, String.format(
+ "Error handling '%s'", event), e);
}
return true;
}
@@ -114,9 +111,7 @@
socket.connect(address);
InputStream inputStream = socket.getInputStream();
- synchronized (mDaemonLock) {
- mOutputStream = socket.getOutputStream();
- }
+ mOutputStream = socket.getOutputStream();
mCallbacks.onDaemonConnected();
@@ -125,10 +120,7 @@
while (true) {
int count = inputStream.read(buffer, start, BUFFER_SIZE - start);
- if (count < 0) {
- loge("got " + count + " reading with start = " + start);
- break;
- }
+ if (count < 0) break;
// Add our starting point to the count and reset the start.
count += start;
@@ -148,10 +140,14 @@
mCallbackHandler.sendMessage(mCallbackHandler.obtainMessage(
event.getCode(), event.getRawEvent()));
} else {
- mResponseQueue.add(event.getCmdNumber(), event);
+ try {
+ mResponseQueue.put(event);
+ } catch (InterruptedException ex) {
+ Slog.e(TAG, "Failed to put response onto queue: " + ex);
+ }
}
} catch (IllegalArgumentException e) {
- log("Problem parsing message: " + rawEvent + " - " + e);
+ Slog.w(TAG, "Problem parsing message: " + rawEvent, e);
}
start = i + 1;
@@ -173,16 +169,15 @@
}
}
} catch (IOException ex) {
- loge("Communications error: " + ex);
+ Slog.e(TAG, "Communications error", ex);
throw ex;
} finally {
synchronized (mDaemonLock) {
if (mOutputStream != null) {
try {
- loge("closing stream for " + mSocket);
mOutputStream.close();
} catch (IOException e) {
- loge("Failed closing output stream: " + e);
+ Slog.w(TAG, "Failed closing output stream", e);
}
mOutputStream = null;
}
@@ -193,17 +188,17 @@
socket.close();
}
} catch (IOException ex) {
- loge("Failed closing socket: " + ex);
+ Slog.w(TAG, "Failed closing socket", ex);
}
}
}
/**
- * Make command for daemon, escaping arguments as needed.
+ * Send command to daemon, escaping arguments as needed.
*
- * @return the final command.
+ * @return the final command issued.
*/
- private StringBuilder makeCommand(String cmd, Object... args)
+ private String sendCommandLocked(String cmd, Object... args)
throws NativeDaemonConnectorException {
// TODO: eventually enforce that cmd doesn't contain arguments
if (cmd.indexOf('\0') >= 0) {
@@ -221,33 +216,22 @@
appendEscaped(builder, argString);
}
- return builder;
- }
-
- private int sendCommand(StringBuilder builder)
- throws NativeDaemonConnectorException {
-
- int sequenceNumber = mSequenceNumber.incrementAndGet();
-
- builder.insert(0, Integer.toString(sequenceNumber) + " ");
-
- if (LOGD) log("SND -> {" + builder.toString() + "}");
+ final String unterminated = builder.toString();
+ log("SND -> {" + unterminated + "}");
builder.append('\0');
- synchronized (mDaemonLock) {
- if (mOutputStream == null) {
- throw new NativeDaemonConnectorException("missing output stream");
- } else {
- try {
- mOutputStream.write(builder.toString().getBytes(Charsets.UTF_8));
- } catch (IOException e) {
- throw new NativeDaemonConnectorException("problem sending command", e);
- }
+ if (mOutputStream == null) {
+ throw new NativeDaemonConnectorException("missing output stream");
+ } else {
+ try {
+ mOutputStream.write(builder.toString().getBytes(Charsets.UTF_8));
+ } catch (IOException e) {
+ throw new NativeDaemonConnectorException("problem sending command", e);
}
}
- return sequenceNumber;
+ return unterminated;
}
/**
@@ -308,41 +292,39 @@
*/
public NativeDaemonEvent[] executeForList(String cmd, Object... args)
throws NativeDaemonConnectorException {
- return execute(DEFAULT_TIMEOUT, cmd, args);
+ synchronized (mDaemonLock) {
+ return executeLocked(cmd, args);
+ }
}
- /**
- * Issue the given command to the native daemon and return any
- * {@linke NativeDaemonEvent@isClassContinue()} responses, including the
- * final terminal response.
- *
- * @throws NativeDaemonConnectorException when problem communicating with
- * native daemon, or if the response matches
- * {@link NativeDaemonEvent#isClassClientError()} or
- * {@link NativeDaemonEvent#isClassServerError()}.
- */
- public NativeDaemonEvent[] execute(int timeout, String cmd, Object... args)
+ private NativeDaemonEvent[] executeLocked(String cmd, Object... args)
throws NativeDaemonConnectorException {
final ArrayList<NativeDaemonEvent> events = Lists.newArrayList();
- final StringBuilder sentCommand = makeCommand(cmd, args);
- final int cmdNumber = sendCommand(sentCommand);
+
+ while (mResponseQueue.size() > 0) {
+ try {
+ log("ignoring {" + mResponseQueue.take() + "}");
+ } catch (Exception e) {}
+ }
+
+ final String sentCommand = sendCommandLocked(cmd, args);
NativeDaemonEvent event = null;
- cmd = sentCommand.toString();
do {
- event = mResponseQueue.remove(cmdNumber, timeout, cmd);
- if (event == null) {
- loge("timed-out waiting for response to " + cmdNumber + " " + cmd);
- throw new NativeDaemonFailureException(cmd, event);
+ try {
+ event = mResponseQueue.take();
+ } catch (InterruptedException e) {
+ Slog.w(TAG, "interrupted waiting for event line");
+ continue;
}
events.add(event);
} while (event.isClassContinue());
if (event.isClassClientError()) {
- throw new NativeDaemonArgumentException(cmd, event);
+ throw new NativeDaemonArgumentException(sentCommand, event);
}
if (event.isClassServerError()) {
- throw new NativeDaemonFailureException(cmd, event);
+ throw new NativeDaemonFailureException(sentCommand, event);
}
return events.toArray(new NativeDaemonEvent[events.size()]);
@@ -466,115 +448,10 @@
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
mLocalLog.dump(fd, pw, args);
- pw.println();
- mResponseQueue.dump(fd, pw, args);
}
private void log(String logstring) {
if (LOGD) Slog.d(TAG, logstring);
mLocalLog.log(logstring);
}
-
- private void loge(String logstring) {
- Slog.e(TAG, logstring);
- mLocalLog.log(logstring);
- }
-
- private static class ResponseQueue {
-
- private static class Response {
- public int cmdNum;
- public LinkedList<NativeDaemonEvent> responses = new LinkedList<NativeDaemonEvent>();
- public String request;
- public Response(int c, String r) {cmdNum = c; request = r;}
- }
-
- private final LinkedList<Response> mResponses;
- private int mMaxCount;
-
- ResponseQueue(int maxCount) {
- mResponses = new LinkedList<Response>();
- mMaxCount = maxCount;
- }
-
- public void add(int cmdNum, NativeDaemonEvent response) {
- Response found = null;
- synchronized (mResponses) {
- for (Response r : mResponses) {
- if (r.cmdNum == cmdNum) {
- found = r;
- break;
- }
- }
- if (found == null) {
- // didn't find it - make sure our queue isn't too big before adding
- // another..
- while (mResponses.size() >= mMaxCount) {
- Slog.e("NativeDaemonConnector.ResponseQueue",
- "more buffered than allowed: " + mResponses.size() +
- " >= " + mMaxCount);
- mResponses.remove();
- }
- found = new Response(cmdNum, null);
- mResponses.add(found);
- }
- found.responses.add(response);
- }
- synchronized (found) {
- found.notify();
- }
- }
-
- public NativeDaemonEvent remove(int cmdNum, int timeoutMs, String origCmd) {
- long endTime = SystemClock.uptimeMillis() + timeoutMs;
- long nowTime;
- Response found = null;
- while (true) {
- synchronized (mResponses) {
- for (Response response : mResponses) {
- if (response.cmdNum == cmdNum) {
- found = response;
- // how many response fragments are left
- switch (response.responses.size()) {
- case 0: // haven't got any - must wait
- break;
- case 1: // last one - remove this from the master list
- mResponses.remove(response); // fall through
- default: // take one and move on
- response.request = origCmd;
- return response.responses.remove();
- }
- }
- }
- nowTime = SystemClock.uptimeMillis();
- if (endTime <= nowTime) {
- Slog.e("NativeDaemonConnector.ResponseQueue",
- "Timeout waiting for response");
- return null;
- }
- /* pre-allocate so we have something unique to wait on */
- if (found == null) {
- found = new Response(cmdNum, origCmd);
- mResponses.add(found);
- }
- }
- try {
- synchronized (found) {
- found.wait(endTime - nowTime);
- }
- } catch (InterruptedException e) {
- // loop around to check if we're done or if it's time to stop waiting
- }
- }
- }
-
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println("Pending requests:");
- synchronized (mResponses) {
- for (Response response : mResponses) {
- pw.println(" Cmd " + response.cmdNum + " - " + response.request);
- }
- }
- }
- }
}
diff --git a/services/java/com/android/server/NativeDaemonEvent.java b/services/java/com/android/server/NativeDaemonEvent.java
index 50ba6d1..62084c0 100644
--- a/services/java/com/android/server/NativeDaemonEvent.java
+++ b/services/java/com/android/server/NativeDaemonEvent.java
@@ -28,22 +28,16 @@
// TODO: keep class ranges in sync with ResponseCode.h
// TODO: swap client and server error ranges to roughly mirror HTTP spec
- private final int mCmdNumber;
private final int mCode;
private final String mMessage;
private final String mRawEvent;
- private NativeDaemonEvent(int cmdNumber, int code, String message, String rawEvent) {
- mCmdNumber = cmdNumber;
+ private NativeDaemonEvent(int code, String message, String rawEvent) {
mCode = code;
mMessage = message;
mRawEvent = rawEvent;
}
- public int getCmdNumber() {
- return mCmdNumber;
- }
-
public int getCode() {
return mCode;
}
@@ -116,28 +110,20 @@
* from native side.
*/
public static NativeDaemonEvent parseRawEvent(String rawEvent) {
- final String[] parsed = rawEvent.split(" ");
- if (parsed.length < 3) {
+ final int splitIndex = rawEvent.indexOf(' ');
+ if (splitIndex == -1) {
throw new IllegalArgumentException("unable to find ' ' separator");
}
- final int cmdNumber;
- try {
- cmdNumber = Integer.parseInt(parsed[0]);
- } catch (NumberFormatException e) {
- throw new IllegalArgumentException("problem parsing cmdNumber", e);
- }
-
final int code;
try {
- code = Integer.parseInt(parsed[1]);
+ code = Integer.parseInt(rawEvent.substring(0, splitIndex));
} catch (NumberFormatException e) {
throw new IllegalArgumentException("problem parsing code", e);
}
- final String message = rawEvent.substring(parsed[0].length() + parsed[1].length() + 2);
-
- return new NativeDaemonEvent(cmdNumber, code, message, rawEvent);
+ final String message = rawEvent.substring(splitIndex + 1);
+ return new NativeDaemonEvent(code, message, rawEvent);
}
/**
diff --git a/services/java/com/android/server/NetworkTimeUpdateService.java b/services/java/com/android/server/NetworkTimeUpdateService.java
index a7d1992..1ff914f 100644
--- a/services/java/com/android/server/NetworkTimeUpdateService.java
+++ b/services/java/com/android/server/NetworkTimeUpdateService.java
@@ -55,7 +55,7 @@
private static final int EVENT_AUTO_TIME_CHANGED = 1;
private static final int EVENT_POLL_NETWORK_TIME = 2;
- private static final int EVENT_WIFI_CONNECTED = 3;
+ private static final int EVENT_NETWORK_CONNECTED = 3;
/** Normal polling frequency */
private static final long POLLING_INTERVAL_MS = 24L * 60 * 60 * 1000; // 24 hrs
@@ -240,8 +240,9 @@
if (netInfo != null) {
// Verify that it's a WIFI connection
if (netInfo.getState() == NetworkInfo.State.CONNECTED &&
- netInfo.getType() == ConnectivityManager.TYPE_WIFI ) {
- mHandler.obtainMessage(EVENT_WIFI_CONNECTED).sendToTarget();
+ (netInfo.getType() == ConnectivityManager.TYPE_WIFI ||
+ netInfo.getType() == ConnectivityManager.TYPE_ETHERNET) ) {
+ mHandler.obtainMessage(EVENT_NETWORK_CONNECTED).sendToTarget();
}
}
}
@@ -260,7 +261,7 @@
switch (msg.what) {
case EVENT_AUTO_TIME_CHANGED:
case EVENT_POLL_NETWORK_TIME:
- case EVENT_WIFI_CONNECTED:
+ case EVENT_NETWORK_CONNECTED:
onPollNetworkTime(msg.what);
break;
}
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index bb0ac3e..e953355 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -50,6 +50,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.os.WorkSource;
import android.provider.Settings;
import android.util.EventLog;
@@ -176,6 +177,7 @@
private boolean mDoneBooting = false;
private boolean mBootCompleted = false;
+ private boolean mHeadless = false;
private int mStayOnConditions = 0;
private final int[] mBroadcastQueue = new int[] { -1, -1, -1 };
private final int[] mBroadcastWhy = new int[3];
@@ -530,6 +532,7 @@
mButtonLight = lights.getLight(LightsService.LIGHT_ID_BUTTONS);
mKeyboardLight = lights.getLight(LightsService.LIGHT_ID_KEYBOARD);
mAttentionLight = lights.getLight(LightsService.LIGHT_ID_ATTENTION);
+ mHeadless = "1".equals(SystemProperties.get("ro.config.headless", "0"));
nativeInit();
synchronized (mLocks) {
@@ -1894,9 +1897,11 @@
}
private void updateNativePowerStateLocked() {
- nativeSetPowerState(
- (mPowerState & SCREEN_ON_BIT) != 0,
- (mPowerState & SCREEN_BRIGHT) == SCREEN_BRIGHT);
+ if (!mHeadless) {
+ nativeSetPowerState(
+ (mPowerState & SCREEN_ON_BIT) != 0,
+ (mPowerState & SCREEN_BRIGHT) == SCREEN_BRIGHT);
+ }
}
private int screenOffFinishedAnimatingLocked(int reason) {
@@ -2240,11 +2245,13 @@
mScreenOffHandler.postAtTime(this, now+(1000/60));
}
} else {
- // It's pretty scary to hold mLocks for this long, and we should
- // redesign this, but it works for now.
- nativeStartSurfaceFlingerAnimation(
- mScreenOffReason == WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR
- ? 0 : mAnimationSetting);
+ if (!mHeadless) {
+ // It's pretty scary to hold mLocks for this long, and we should
+ // redesign this, but it works for now.
+ nativeStartSurfaceFlingerAnimation(
+ mScreenOffReason == WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR
+ ? 0 : mAnimationSetting);
+ }
mScreenBrightness.jumpToTargetLocked();
}
}
diff --git a/services/java/com/android/server/SerialService.java b/services/java/com/android/server/SerialService.java
new file mode 100644
index 0000000..5d2b2a0
--- /dev/null
+++ b/services/java/com/android/server/SerialService.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2011 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 an
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.content.Context;
+import android.hardware.ISerialManager;
+import android.os.ParcelFileDescriptor;
+
+import java.io.File;
+import java.util.ArrayList;
+
+public class SerialService extends ISerialManager.Stub {
+
+ private final Context mContext;
+ private final String[] mSerialPorts;
+
+ public SerialService(Context context) {
+ mContext = context;
+ mSerialPorts = context.getResources().getStringArray(
+ com.android.internal.R.array.config_serialPorts);
+ }
+
+ public String[] getSerialPorts() {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SERIAL_PORT, null);
+
+ ArrayList<String> ports = new ArrayList<String>();
+ for (int i = 0; i < mSerialPorts.length; i++) {
+ String path = mSerialPorts[i];
+ if (new File(path).exists()) {
+ ports.add(path);
+ }
+ }
+ String[] result = new String[ports.size()];
+ ports.toArray(result);
+ return result;
+ }
+
+ public ParcelFileDescriptor openSerialPort(String path) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SERIAL_PORT, null);
+ return native_open(path);
+ }
+
+ private native ParcelFileDescriptor native_open(String path);
+}
diff --git a/services/java/com/android/server/SystemBackupAgent.java b/services/java/com/android/server/SystemBackupAgent.java
index da97089..a7a583c 100644
--- a/services/java/com/android/server/SystemBackupAgent.java
+++ b/services/java/com/android/server/SystemBackupAgent.java
@@ -44,12 +44,16 @@
private static final String WALLPAPER_IMAGE_FILENAME = "wallpaper";
private static final String WALLPAPER_INFO_FILENAME = "wallpaper_info.xml";
- private static final String WALLPAPER_IMAGE_DIR = "/data/data/com.android.settings/files";
- private static final String WALLPAPER_IMAGE = WALLPAPER_IMAGE_DIR + "/" + WALLPAPER_IMAGE_FILENAME;
+ // TODO: Will need to change if backing up non-primary user's wallpaper
+ private static final String WALLPAPER_IMAGE_DIR = "/data/system/users/0";
+ private static final String WALLPAPER_IMAGE = WallpaperBackupHelper.WALLPAPER_IMAGE;
- private static final String WALLPAPER_INFO_DIR = "/data/system";
- private static final String WALLPAPER_INFO = WALLPAPER_INFO_DIR + "/" + WALLPAPER_INFO_FILENAME;
-
+ // TODO: Will need to change if backing up non-primary user's wallpaper
+ private static final String WALLPAPER_INFO_DIR = "/data/system/users/0";
+ private static final String WALLPAPER_INFO = WallpaperBackupHelper.WALLPAPER_INFO;
+ // Use old keys to keep legacy data compatibility and avoid writing two wallpapers
+ private static final String WALLPAPER_IMAGE_KEY = WallpaperBackupHelper.WALLPAPER_IMAGE_KEY;
+ private static final String WALLPAPER_INFO_KEY = WallpaperBackupHelper.WALLPAPER_INFO_KEY;
@Override
public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
@@ -58,13 +62,15 @@
WallpaperManagerService wallpaper = (WallpaperManagerService)ServiceManager.getService(
Context.WALLPAPER_SERVICE);
String[] files = new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO };
- if (wallpaper != null && wallpaper.mName != null && wallpaper.mName.length() > 0) {
+ String[] keys = new String[] { WALLPAPER_IMAGE_KEY, WALLPAPER_INFO_KEY };
+ if (wallpaper != null && wallpaper.getName() != null && wallpaper.getName().length() > 0) {
// When the wallpaper has a name, back up the info by itself.
// TODO: Don't rely on the innards of the service object like this!
// TODO: Send a delete for any stored wallpaper image in this case?
files = new String[] { WALLPAPER_INFO };
+ keys = new String[] { WALLPAPER_INFO_KEY };
}
- addHelper("wallpaper", new WallpaperBackupHelper(SystemBackupAgent.this, files));
+ addHelper("wallpaper", new WallpaperBackupHelper(SystemBackupAgent.this, files, keys));
super.onBackup(oldState, data, newState);
}
@@ -90,9 +96,11 @@
throws IOException {
// On restore, we also support a previous data schema "system_files"
addHelper("wallpaper", new WallpaperBackupHelper(SystemBackupAgent.this,
- new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO }));
+ new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO },
+ new String[] { WALLPAPER_IMAGE_KEY, WALLPAPER_INFO_KEY} ));
addHelper("system_files", new WallpaperBackupHelper(SystemBackupAgent.this,
- new String[] { WALLPAPER_IMAGE }));
+ new String[] { WALLPAPER_IMAGE },
+ new String[] { WALLPAPER_IMAGE_KEY} ));
try {
super.onRestore(data, appVersionCode, newState);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 762acbb..0dbc7c3 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -108,6 +108,7 @@
String factoryTestStr = SystemProperties.get("ro.factorytest");
int factoryTest = "".equals(factoryTestStr) ? SystemServer.FACTORY_TEST_OFF
: Integer.parseInt(factoryTestStr);
+ final boolean headless = "1".equals(SystemProperties.get("ro.config.headless", "0"));
LightsService lights = null;
PowerManagerService power = null;
@@ -126,6 +127,7 @@
BluetoothA2dpService bluetoothA2dp = null;
DockObserver dock = null;
UsbService usb = null;
+ SerialService serial = null;
UiModeManagerService uiMode = null;
RecognitionManagerService recognition = null;
ThrottleService throttle = null;
@@ -231,10 +233,13 @@
bluetooth = new BluetoothService(context);
ServiceManager.addService(BluetoothAdapter.BLUETOOTH_SERVICE, bluetooth);
bluetooth.initAfterRegistration();
- bluetoothA2dp = new BluetoothA2dpService(context, bluetooth);
- ServiceManager.addService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE,
- bluetoothA2dp);
- bluetooth.initAfterA2dpRegistration();
+
+ if (!"0".equals(SystemProperties.get("system_init.startaudioservice"))) {
+ bluetoothA2dp = new BluetoothA2dpService(context, bluetooth);
+ ServiceManager.addService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE,
+ bluetoothA2dp);
+ bluetooth.initAfterA2dpRegistration();
+ }
int airplaneModeOn = Settings.System.getInt(mContentResolver,
Settings.System.AIRPLANE_MODE_ON, 0);
@@ -396,15 +401,17 @@
reportWtf("starting ThrottleService", e);
}
- try {
- /*
- * NotificationManagerService is dependant on MountService,
- * (for media / usb notifications) so we must start MountService first.
- */
- Slog.i(TAG, "Mount Service");
- ServiceManager.addService("mount", new MountService(context));
- } catch (Throwable e) {
- reportWtf("starting Mount Service", e);
+ if (!"0".equals(SystemProperties.get("system_init.startmountservice"))) {
+ try {
+ /*
+ * NotificationManagerService is dependant on MountService,
+ * (for media / usb notifications) so we must start MountService first.
+ */
+ Slog.i(TAG, "Mount Service");
+ ServiceManager.addService("mount", new MountService(context));
+ } catch (Throwable e) {
+ reportWtf("starting Mount Service", e);
+ }
}
try {
@@ -456,19 +463,26 @@
reportWtf("starting DropBoxManagerService", e);
}
- try {
- Slog.i(TAG, "Wallpaper Service");
- wallpaper = new WallpaperManagerService(context);
- ServiceManager.addService(Context.WALLPAPER_SERVICE, wallpaper);
- } catch (Throwable e) {
- reportWtf("starting Wallpaper Service", e);
+ if (context.getResources().getBoolean(
+ com.android.internal.R.bool.config_enableWallpaperService)) {
+ try {
+ Slog.i(TAG, "Wallpaper Service");
+ if (!headless) {
+ wallpaper = new WallpaperManagerService(context);
+ ServiceManager.addService(Context.WALLPAPER_SERVICE, wallpaper);
+ }
+ } catch (Throwable e) {
+ reportWtf("starting Wallpaper Service", e);
+ }
}
- try {
- Slog.i(TAG, "Audio Service");
- ServiceManager.addService(Context.AUDIO_SERVICE, new AudioService(context));
- } catch (Throwable e) {
- reportWtf("starting Audio Service", e);
+ if (!"0".equals(SystemProperties.get("system_init.startaudioservice"))) {
+ try {
+ Slog.i(TAG, "Audio Service");
+ ServiceManager.addService(Context.AUDIO_SERVICE, new AudioService(context));
+ } catch (Throwable e) {
+ reportWtf("starting Audio Service", e);
+ }
}
try {
@@ -497,6 +511,15 @@
}
try {
+ Slog.i(TAG, "Serial Service");
+ // Serial port support
+ serial = new SerialService(context);
+ ServiceManager.addService(Context.SERIAL_SERVICE, serial);
+ } catch (Throwable e) {
+ Slog.e(TAG, "Failure starting SerialService", e);
+ }
+
+ try {
Slog.i(TAG, "UI Mode Manager Service");
// Listen for UI mode changes
uiMode = new UiModeManagerService(context);
@@ -642,7 +665,7 @@
public void run() {
Slog.i(TAG, "Making services ready");
- startSystemUi(contextF);
+ if (!headless) startSystemUi(contextF);
try {
if (batteryF != null) batteryF.systemReady();
} catch (Throwable e) {
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index 4925a4e..8ee12bc 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -24,6 +24,7 @@
import android.app.PendingIntent;
import android.app.WallpaperInfo;
import android.app.backup.BackupManager;
+import android.app.backup.WallpaperBackupHelper;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -43,11 +44,13 @@
import android.os.RemoteCallbackList;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.os.UserId;
import android.service.wallpaper.IWallpaperConnection;
import android.service.wallpaper.IWallpaperEngine;
import android.service.wallpaper.IWallpaperService;
import android.service.wallpaper.WallpaperService;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.Xml;
import android.view.Display;
import android.view.IWindowManager;
@@ -70,6 +73,7 @@
import com.android.internal.content.PackageMonitor;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.JournaledFile;
+import com.android.server.am.ActivityManagerService;
class WallpaperManagerService extends IWallpaperManager.Stub {
static final String TAG = "WallpaperService";
@@ -83,17 +87,9 @@
*/
static final long MIN_WALLPAPER_CRASH_TIME = 10000;
- static final File WALLPAPER_DIR = new File(
- "/data/data/com.android.settings/files");
+ static final File WALLPAPER_BASE_DIR = new File("/data/system/users");
static final String WALLPAPER = "wallpaper";
- static final File WALLPAPER_FILE = new File(WALLPAPER_DIR, WALLPAPER);
-
- /**
- * List of callbacks registered they should each be notified
- * when the wallpaper is changed.
- */
- private final RemoteCallbackList<IWallpaperManagerCallback> mCallbacks
- = new RemoteCallbackList<IWallpaperManagerCallback>();
+ static final String WALLPAPER_INFO = "wallpaper_info.xml";
/**
* Observes the wallpaper for changes and notifies all IWallpaperServiceCallbacks
@@ -101,97 +97,135 @@
* wallpaper set and is created for the first time. The CLOSE_WRITE is triggered
* everytime the wallpaper is changed.
*/
- private final FileObserver mWallpaperObserver = new FileObserver(
- WALLPAPER_DIR.getAbsolutePath(), CLOSE_WRITE | DELETE | DELETE_SELF) {
- @Override
- public void onEvent(int event, String path) {
- if (path == null) {
- return;
- }
- synchronized (mLock) {
- // changing the wallpaper means we'll need to back up the new one
- long origId = Binder.clearCallingIdentity();
- BackupManager bm = new BackupManager(mContext);
- bm.dataChanged();
- Binder.restoreCallingIdentity(origId);
+ private class WallpaperObserver extends FileObserver {
- File changedFile = new File(WALLPAPER_DIR, path);
- if (WALLPAPER_FILE.equals(changedFile)) {
- notifyCallbacksLocked();
- if (mWallpaperComponent == null || event != CLOSE_WRITE
- || mImageWallpaperPending) {
- if (event == CLOSE_WRITE) {
- mImageWallpaperPending = false;
- }
- bindWallpaperComponentLocked(mImageWallpaperComponent,
- true, false);
- saveSettingsLocked();
- }
+ final WallpaperData mWallpaper;
+ final File mWallpaperDir;
+ final File mWallpaperFile;
+
+ public WallpaperObserver(WallpaperData wallpaper) {
+ super(getWallpaperDir(wallpaper.userId).getAbsolutePath(),
+ CLOSE_WRITE | DELETE | DELETE_SELF);
+ mWallpaperDir = getWallpaperDir(wallpaper.userId);
+ mWallpaper = wallpaper;
+ mWallpaperFile = new File(mWallpaperDir, WALLPAPER);
+ }
+
+ @Override
+ public void onEvent(int event, String path) {
+ if (path == null) {
+ return;
+ }
+ synchronized (mLock) {
+ // changing the wallpaper means we'll need to back up the new one
+ long origId = Binder.clearCallingIdentity();
+ BackupManager bm = new BackupManager(mContext);
+ bm.dataChanged();
+ Binder.restoreCallingIdentity(origId);
+
+ File changedFile = new File(mWallpaperDir, path);
+ if (mWallpaperFile.equals(changedFile)) {
+ notifyCallbacksLocked(mWallpaper);
+ if (mWallpaper.wallpaperComponent == null || event != CLOSE_WRITE
+ || mWallpaper.imageWallpaperPending) {
+ if (event == CLOSE_WRITE) {
+ mWallpaper.imageWallpaperPending = false;
}
+ bindWallpaperComponentLocked(mWallpaper.imageWallpaperComponent, true,
+ false, mWallpaper);
+ saveSettingsLocked(mWallpaper);
}
}
- };
-
+ }
+ }
+ }
+
final Context mContext;
final IWindowManager mIWindowManager;
final MyPackageMonitor mMonitor;
+ WallpaperData mLastWallpaper;
- int mWidth = -1;
- int mHeight = -1;
+ SparseArray<WallpaperData> mWallpaperMap = new SparseArray<WallpaperData>();
- /**
- * Client is currently writing a new image wallpaper.
- */
- boolean mImageWallpaperPending;
+ int mCurrentUserId;
- /**
- * Resource name if using a picture from the wallpaper gallery
- */
- String mName = "";
-
- /**
- * The component name of the currently set live wallpaper.
- */
- ComponentName mWallpaperComponent;
-
- /**
- * The component name of the wallpaper that should be set next.
- */
- ComponentName mNextWallpaperComponent;
-
- /**
- * Name of the component used to display bitmap wallpapers from either the gallery or
- * built-in wallpapers.
- */
- ComponentName mImageWallpaperComponent = new ComponentName("com.android.systemui",
- "com.android.systemui.ImageWallpaper");
-
- WallpaperConnection mWallpaperConnection;
- long mLastDiedTime;
- boolean mWallpaperUpdating;
-
+ static class WallpaperData {
+
+ int userId;
+
+ File wallpaperFile;
+
+ /**
+ * Client is currently writing a new image wallpaper.
+ */
+ boolean imageWallpaperPending;
+
+ /**
+ * Resource name if using a picture from the wallpaper gallery
+ */
+ String name = "";
+
+ /**
+ * The component name of the currently set live wallpaper.
+ */
+ ComponentName wallpaperComponent;
+
+ /**
+ * The component name of the wallpaper that should be set next.
+ */
+ ComponentName nextWallpaperComponent;
+
+ /**
+ * Name of the component used to display bitmap wallpapers from either the gallery or
+ * built-in wallpapers.
+ */
+ ComponentName imageWallpaperComponent = new ComponentName("com.android.systemui",
+ "com.android.systemui.ImageWallpaper");
+
+ WallpaperConnection connection;
+ long lastDiedTime;
+ boolean wallpaperUpdating;
+ WallpaperObserver wallpaperObserver;
+
+ /**
+ * List of callbacks registered they should each be notified when the wallpaper is changed.
+ */
+ private RemoteCallbackList<IWallpaperManagerCallback> callbacks
+ = new RemoteCallbackList<IWallpaperManagerCallback>();
+
+ int width = -1;
+ int height = -1;
+
+ WallpaperData(int userId) {
+ this.userId = userId;
+ wallpaperFile = new File(getWallpaperDir(userId), WALLPAPER);
+ }
+ }
+
class WallpaperConnection extends IWallpaperConnection.Stub
implements ServiceConnection {
final WallpaperInfo mInfo;
final Binder mToken = new Binder();
IWallpaperService mService;
IWallpaperEngine mEngine;
+ WallpaperData mWallpaper;
- public WallpaperConnection(WallpaperInfo info) {
+ public WallpaperConnection(WallpaperInfo info, WallpaperData wallpaper) {
mInfo = info;
+ mWallpaper = wallpaper;
}
public void onServiceConnected(ComponentName name, IBinder service) {
synchronized (mLock) {
- if (mWallpaperConnection == this) {
- mLastDiedTime = SystemClock.uptimeMillis();
+ if (mWallpaper.connection == this) {
+ mWallpaper.lastDiedTime = SystemClock.uptimeMillis();
mService = IWallpaperService.Stub.asInterface(service);
- attachServiceLocked(this);
+ attachServiceLocked(this, mWallpaper);
// XXX should probably do saveSettingsLocked() later
// when we have an engine, but I'm not sure about
// locking there and anyway we always need to be able to
// recover if there is something wrong.
- saveSettingsLocked();
+ saveSettingsLocked(mWallpaper);
}
}
}
@@ -200,43 +234,50 @@
synchronized (mLock) {
mService = null;
mEngine = null;
- if (mWallpaperConnection == this) {
- Slog.w(TAG, "Wallpaper service gone: " + mWallpaperComponent);
- if (!mWallpaperUpdating && (mLastDiedTime+MIN_WALLPAPER_CRASH_TIME)
- > SystemClock.uptimeMillis()) {
+ if (mWallpaper.connection == this) {
+ Slog.w(TAG, "Wallpaper service gone: " + mWallpaper.wallpaperComponent);
+ if (!mWallpaper.wallpaperUpdating
+ && (mWallpaper.lastDiedTime + MIN_WALLPAPER_CRASH_TIME)
+ > SystemClock.uptimeMillis()
+ && mWallpaper.userId == mCurrentUserId) {
Slog.w(TAG, "Reverting to built-in wallpaper!");
- clearWallpaperLocked(true);
+ clearWallpaperLocked(true, mWallpaper.userId);
}
}
}
}
-
+
public void attachEngine(IWallpaperEngine engine) {
mEngine = engine;
}
-
+
public ParcelFileDescriptor setWallpaper(String name) {
synchronized (mLock) {
- if (mWallpaperConnection == this) {
- return updateWallpaperBitmapLocked(name);
+ if (mWallpaper.connection == this) {
+ return updateWallpaperBitmapLocked(name, mWallpaper);
}
return null;
}
}
}
-
+
class MyPackageMonitor extends PackageMonitor {
@Override
public void onPackageUpdateFinished(String packageName, int uid) {
synchronized (mLock) {
- if (mWallpaperComponent != null &&
- mWallpaperComponent.getPackageName().equals(packageName)) {
- mWallpaperUpdating = false;
- ComponentName comp = mWallpaperComponent;
- clearWallpaperComponentLocked();
- if (!bindWallpaperComponentLocked(comp, false, false)) {
- Slog.w(TAG, "Wallpaper no longer available; reverting to default");
- clearWallpaperLocked(false);
+ for (int i = 0; i < mWallpaperMap.size(); i++) {
+ WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+ if (wallpaper.wallpaperComponent != null
+ && wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
+ wallpaper.wallpaperUpdating = false;
+ ComponentName comp = wallpaper.wallpaperComponent;
+ clearWallpaperComponentLocked(wallpaper);
+ // Do this only for the current user's wallpaper
+ if (wallpaper.userId == mCurrentUserId
+ && !bindWallpaperComponentLocked(comp, false, false, wallpaper)) {
+ Slog.w(TAG, "Wallpaper no longer available; reverting to default");
+ clearWallpaperLocked(false, wallpaper.userId);
+ }
}
}
}
@@ -245,72 +286,91 @@
@Override
public void onPackageModified(String packageName) {
synchronized (mLock) {
- if (mWallpaperComponent == null ||
- !mWallpaperComponent.getPackageName().equals(packageName)) {
- return;
+ for (int i = 0; i < mWallpaperMap.size(); i++) {
+ WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+ if (wallpaper.wallpaperComponent == null
+ || !wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
+ continue;
+ }
+ doPackagesChanged(true, wallpaper);
}
}
- doPackagesChanged(true);
}
@Override
public void onPackageUpdateStarted(String packageName, int uid) {
synchronized (mLock) {
- if (mWallpaperComponent != null &&
- mWallpaperComponent.getPackageName().equals(packageName)) {
- mWallpaperUpdating = true;
+ for (int i = 0; i < mWallpaperMap.size(); i++) {
+ WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+ if (wallpaper.wallpaperComponent != null
+ && wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
+ wallpaper.wallpaperUpdating = true;
+ }
}
}
}
@Override
public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
- return doPackagesChanged(doit);
+ boolean changed = false;
+ for (int i = 0; i < mWallpaperMap.size(); i++) {
+ WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+ boolean res = doPackagesChanged(doit, wallpaper);
+ changed |= res;
+ }
+ return changed;
}
@Override
public void onSomePackagesChanged() {
- doPackagesChanged(true);
+ for (int i = 0; i < mWallpaperMap.size(); i++) {
+ WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+ doPackagesChanged(true, wallpaper);
+ }
}
-
- boolean doPackagesChanged(boolean doit) {
+
+ boolean doPackagesChanged(boolean doit, WallpaperData wallpaper) {
boolean changed = false;
synchronized (mLock) {
- if (mWallpaperComponent != null) {
- int change = isPackageDisappearing(mWallpaperComponent.getPackageName());
+ if (wallpaper.wallpaperComponent != null) {
+ int change = isPackageDisappearing(wallpaper.wallpaperComponent
+ .getPackageName());
if (change == PACKAGE_PERMANENT_CHANGE
|| change == PACKAGE_TEMPORARY_CHANGE) {
changed = true;
if (doit) {
- Slog.w(TAG, "Wallpaper uninstalled, removing: " + mWallpaperComponent);
- clearWallpaperLocked(false);
+ Slog.w(TAG, "Wallpaper uninstalled, removing: "
+ + wallpaper.wallpaperComponent);
+ clearWallpaperLocked(false, wallpaper.userId);
}
}
}
- if (mNextWallpaperComponent != null) {
- int change = isPackageDisappearing(mNextWallpaperComponent.getPackageName());
+ if (wallpaper.nextWallpaperComponent != null) {
+ int change = isPackageDisappearing(wallpaper.nextWallpaperComponent
+ .getPackageName());
if (change == PACKAGE_PERMANENT_CHANGE
|| change == PACKAGE_TEMPORARY_CHANGE) {
- mNextWallpaperComponent = null;
+ wallpaper.nextWallpaperComponent = null;
}
}
- if (mWallpaperComponent != null
- && isPackageModified(mWallpaperComponent.getPackageName())) {
+ if (wallpaper.wallpaperComponent != null
+ && isPackageModified(wallpaper.wallpaperComponent.getPackageName())) {
try {
mContext.getPackageManager().getServiceInfo(
- mWallpaperComponent, 0);
+ wallpaper.wallpaperComponent, 0);
} catch (NameNotFoundException e) {
- Slog.w(TAG, "Wallpaper component gone, removing: " + mWallpaperComponent);
- clearWallpaperLocked(false);
+ Slog.w(TAG, "Wallpaper component gone, removing: "
+ + wallpaper.wallpaperComponent);
+ clearWallpaperLocked(false, wallpaper.userId);
}
}
- if (mNextWallpaperComponent != null
- && isPackageModified(mNextWallpaperComponent.getPackageName())) {
+ if (wallpaper.nextWallpaperComponent != null
+ && isPackageModified(wallpaper.nextWallpaperComponent.getPackageName())) {
try {
mContext.getPackageManager().getServiceInfo(
- mNextWallpaperComponent, 0);
+ wallpaper.nextWallpaperComponent, 0);
} catch (NameNotFoundException e) {
- mNextWallpaperComponent = null;
+ wallpaper.nextWallpaperComponent = null;
}
}
}
@@ -325,51 +385,110 @@
ServiceManager.getService(Context.WINDOW_SERVICE));
mMonitor = new MyPackageMonitor();
mMonitor.register(context, true);
- WALLPAPER_DIR.mkdirs();
- loadSettingsLocked();
- mWallpaperObserver.startWatching();
+ WALLPAPER_BASE_DIR.mkdirs();
+ loadSettingsLocked(0);
}
+ private static File getWallpaperDir(int userId) {
+ return new File(WALLPAPER_BASE_DIR + "/" + userId);
+ }
+
@Override
protected void finalize() throws Throwable {
super.finalize();
- mWallpaperObserver.stopWatching();
+ for (int i = 0; i < mWallpaperMap.size(); i++) {
+ WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+ wallpaper.wallpaperObserver.stopWatching();
+ }
}
public void systemReady() {
if (DEBUG) Slog.v(TAG, "systemReady");
+ WallpaperData wallpaper = mWallpaperMap.get(0);
+ switchWallpaper(wallpaper);
+ wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper);
+ wallpaper.wallpaperObserver.startWatching();
+ ActivityManagerService ams = (ActivityManagerService) ServiceManager
+ .getService(Context.ACTIVITY_SERVICE);
+ ams.addUserListener(new ActivityManagerService.UserListener() {
+
+ @Override
+ public void onUserChanged(int userId) {
+ switchUser(userId);
+ }
+
+ @Override
+ public void onUserAdded(int userId) {
+ }
+
+ @Override
+ public void onUserRemoved(int userId) {
+ }
+
+ @Override
+ public void onUserLoggedOut(int userId) {
+ }
+
+ });
+ }
+
+ String getName() {
+ return mWallpaperMap.get(0).name;
+ }
+
+ void switchUser(int userId) {
+ synchronized (mLock) {
+ mCurrentUserId = userId;
+ WallpaperData wallpaper = mWallpaperMap.get(userId);
+ if (wallpaper == null) {
+ wallpaper = new WallpaperData(userId);
+ mWallpaperMap.put(userId, wallpaper);
+ loadSettingsLocked(userId);
+ wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper);
+ wallpaper.wallpaperObserver.startWatching();
+ }
+ switchWallpaper(wallpaper);
+ }
+ }
+
+ void switchWallpaper(WallpaperData wallpaper) {
synchronized (mLock) {
RuntimeException e = null;
try {
- if (bindWallpaperComponentLocked(mNextWallpaperComponent, false, false)) {
+ ComponentName cname = wallpaper.wallpaperComponent != null ?
+ wallpaper.wallpaperComponent : wallpaper.nextWallpaperComponent;
+ if (bindWallpaperComponentLocked(cname, true, false, wallpaper)) {
return;
}
} catch (RuntimeException e1) {
e = e1;
}
Slog.w(TAG, "Failure starting previous wallpaper", e);
- clearWallpaperLocked(false);
- }
- }
-
- public void clearWallpaper() {
- if (DEBUG) Slog.v(TAG, "clearWallpaper");
- synchronized (mLock) {
- clearWallpaperLocked(false);
+ clearWallpaperLocked(false, wallpaper.userId);
}
}
- public void clearWallpaperLocked(boolean defaultFailed) {
- File f = WALLPAPER_FILE;
+ public void clearWallpaper() {
+ if (DEBUG) Slog.v(TAG, "clearWallpaper");
+ synchronized (mLock) {
+ clearWallpaperLocked(false, UserId.getCallingUserId());
+ }
+ }
+
+ void clearWallpaperLocked(boolean defaultFailed, int userId) {
+ WallpaperData wallpaper = mWallpaperMap.get(userId);
+ File f = new File(getWallpaperDir(userId), WALLPAPER);
if (f.exists()) {
f.delete();
}
final long ident = Binder.clearCallingIdentity();
RuntimeException e = null;
try {
- mImageWallpaperPending = false;
+ wallpaper.imageWallpaperPending = false;
+ if (userId != mCurrentUserId) return;
if (bindWallpaperComponentLocked(defaultFailed
- ? mImageWallpaperComponent : null, true, false)) {
+ ? wallpaper.imageWallpaperComponent
+ : null, true, false, wallpaper)) {
return;
}
} catch (IllegalArgumentException e1) {
@@ -383,29 +502,35 @@
// let's not let it crash the system and just live with no
// wallpaper.
Slog.e(TAG, "Default wallpaper component not found!", e);
- clearWallpaperComponentLocked();
+ clearWallpaperComponentLocked(wallpaper);
}
public void setDimensionHints(int width, int height) throws RemoteException {
checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
+ int userId = UserId.getCallingUserId();
+ WallpaperData wallpaper = mWallpaperMap.get(userId);
+ if (wallpaper == null) {
+ throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
+ }
if (width <= 0 || height <= 0) {
throw new IllegalArgumentException("width and height must be > 0");
}
synchronized (mLock) {
- if (width != mWidth || height != mHeight) {
- mWidth = width;
- mHeight = height;
- saveSettingsLocked();
- if (mWallpaperConnection != null) {
- if (mWallpaperConnection.mEngine != null) {
+ if (width != wallpaper.width || height != wallpaper.height) {
+ wallpaper.width = width;
+ wallpaper.height = height;
+ saveSettingsLocked(wallpaper);
+ if (mCurrentUserId != userId) return; // Don't change the properties now
+ if (wallpaper.connection != null) {
+ if (wallpaper.connection.mEngine != null) {
try {
- mWallpaperConnection.mEngine.setDesiredSize(
+ wallpaper.connection.mEngine.setDesiredSize(
width, height);
} catch (RemoteException e) {
}
- notifyCallbacksLocked();
+ notifyCallbacksLocked(wallpaper);
}
}
}
@@ -414,26 +539,38 @@
public int getWidthHint() throws RemoteException {
synchronized (mLock) {
- return mWidth;
+ WallpaperData wallpaper = mWallpaperMap.get(UserId.getCallingUserId());
+ return wallpaper.width;
}
}
public int getHeightHint() throws RemoteException {
synchronized (mLock) {
- return mHeight;
+ WallpaperData wallpaper = mWallpaperMap.get(UserId.getCallingUserId());
+ return wallpaper.height;
}
}
public ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb,
Bundle outParams) {
synchronized (mLock) {
+ // This returns the current user's wallpaper, if called by a system service. Else it
+ // returns the wallpaper for the calling user.
+ int callingUid = Binder.getCallingUid();
+ int wallpaperUserId = 0;
+ if (callingUid == android.os.Process.SYSTEM_UID) {
+ wallpaperUserId = mCurrentUserId;
+ } else {
+ wallpaperUserId = UserId.getUserId(callingUid);
+ }
+ WallpaperData wallpaper = mWallpaperMap.get(wallpaperUserId);
try {
if (outParams != null) {
- outParams.putInt("width", mWidth);
- outParams.putInt("height", mHeight);
+ outParams.putInt("width", wallpaper.width);
+ outParams.putInt("height", wallpaper.height);
}
- mCallbacks.register(cb);
- File f = WALLPAPER_FILE;
+ wallpaper.callbacks.register(cb);
+ File f = new File(getWallpaperDir(wallpaperUserId), WALLPAPER);
if (!f.exists()) {
return null;
}
@@ -447,24 +584,30 @@
}
public WallpaperInfo getWallpaperInfo() {
+ int userId = UserId.getCallingUserId();
synchronized (mLock) {
- if (mWallpaperConnection != null) {
- return mWallpaperConnection.mInfo;
+ WallpaperData wallpaper = mWallpaperMap.get(userId);
+ if (wallpaper.connection != null) {
+ return wallpaper.connection.mInfo;
}
return null;
}
}
-
+
public ParcelFileDescriptor setWallpaper(String name) {
if (DEBUG) Slog.v(TAG, "setWallpaper");
-
+ int userId = UserId.getCallingUserId();
+ WallpaperData wallpaper = mWallpaperMap.get(userId);
+ if (wallpaper == null) {
+ throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
+ }
checkPermission(android.Manifest.permission.SET_WALLPAPER);
synchronized (mLock) {
final long ident = Binder.clearCallingIdentity();
try {
- ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name);
+ ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name, wallpaper);
if (pfd != null) {
- mImageWallpaperPending = true;
+ wallpaper.imageWallpaperPending = true;
}
return pfd;
} finally {
@@ -473,19 +616,20 @@
}
}
- ParcelFileDescriptor updateWallpaperBitmapLocked(String name) {
+ ParcelFileDescriptor updateWallpaperBitmapLocked(String name, WallpaperData wallpaper) {
if (name == null) name = "";
try {
- if (!WALLPAPER_DIR.exists()) {
- WALLPAPER_DIR.mkdir();
+ File dir = getWallpaperDir(wallpaper.userId);
+ if (!dir.exists()) {
+ dir.mkdir();
FileUtils.setPermissions(
- WALLPAPER_DIR.getPath(),
+ dir.getPath(),
FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
-1, -1);
}
- ParcelFileDescriptor fd = ParcelFileDescriptor.open(WALLPAPER_FILE,
+ ParcelFileDescriptor fd = ParcelFileDescriptor.open(new File(dir, WALLPAPER),
MODE_CREATE|MODE_READ_WRITE);
- mName = name;
+ wallpaper.name = name;
return fd;
} catch (FileNotFoundException e) {
Slog.w(TAG, "Error setting wallpaper", e);
@@ -495,31 +639,36 @@
public void setWallpaperComponent(ComponentName name) {
if (DEBUG) Slog.v(TAG, "setWallpaperComponent name=" + name);
+ int userId = UserId.getCallingUserId();
+ WallpaperData wallpaper = mWallpaperMap.get(userId);
+ if (wallpaper == null) {
+ throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
+ }
checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT);
synchronized (mLock) {
final long ident = Binder.clearCallingIdentity();
try {
- mImageWallpaperPending = false;
- bindWallpaperComponentLocked(name, false, true);
+ wallpaper.imageWallpaperPending = false;
+ bindWallpaperComponentLocked(name, false, true, wallpaper);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
}
- boolean bindWallpaperComponentLocked(ComponentName componentName, boolean force, boolean fromUser) {
+ boolean bindWallpaperComponentLocked(ComponentName componentName, boolean force,
+ boolean fromUser, WallpaperData wallpaper) {
if (DEBUG) Slog.v(TAG, "bindWallpaperComponentLocked: componentName=" + componentName);
-
// Has the component changed?
if (!force) {
- if (mWallpaperConnection != null) {
- if (mWallpaperComponent == null) {
+ if (wallpaper.connection != null) {
+ if (wallpaper.wallpaperComponent == null) {
if (componentName == null) {
if (DEBUG) Slog.v(TAG, "bindWallpaperComponentLocked: still using default");
// Still using default wallpaper.
return true;
}
- } else if (mWallpaperComponent.equals(componentName)) {
+ } else if (wallpaper.wallpaperComponent.equals(componentName)) {
// Changing to same wallpaper.
if (DEBUG) Slog.v(TAG, "same wallpaper");
return true;
@@ -538,7 +687,7 @@
}
if (componentName == null) {
// Fall back to static image wallpaper
- componentName = mImageWallpaperComponent;
+ componentName = wallpaper.imageWallpaperComponent;
//clearWallpaperComponentLocked();
//return;
if (DEBUG) Slog.v(TAG, "Using image wallpaper");
@@ -560,7 +709,7 @@
WallpaperInfo wi = null;
Intent intent = new Intent(WallpaperService.SERVICE_INTERFACE);
- if (componentName != null && !componentName.equals(mImageWallpaperComponent)) {
+ if (componentName != null && !componentName.equals(wallpaper.imageWallpaperComponent)) {
// Make sure the selected service is actually a wallpaper service.
List<ResolveInfo> ris = mContext.getPackageManager()
.queryIntentServices(intent, PackageManager.GET_META_DATA);
@@ -599,8 +748,13 @@
// Bind the service!
if (DEBUG) Slog.v(TAG, "Binding to:" + componentName);
- WallpaperConnection newConn = new WallpaperConnection(wi);
+ WallpaperConnection newConn = new WallpaperConnection(wi, wallpaper);
intent.setComponent(componentName);
+ int serviceUserId = wallpaper.userId;
+ // Because the image wallpaper is running in the system ui
+ if (componentName.equals(wallpaper.imageWallpaperComponent)) {
+ serviceUserId = 0;
+ }
intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
com.android.internal.R.string.wallpaper_binding_label);
intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
@@ -608,8 +762,7 @@
Intent.createChooser(new Intent(Intent.ACTION_SET_WALLPAPER),
mContext.getText(com.android.internal.R.string.chooser_wallpaper)),
0));
- if (!mContext.bindService(intent, newConn,
- Context.BIND_AUTO_CREATE)) {
+ if (!mContext.bindService(intent, newConn, Context.BIND_AUTO_CREATE, serviceUserId)) {
String msg = "Unable to bind service: "
+ componentName;
if (fromUser) {
@@ -618,18 +771,22 @@
Slog.w(TAG, msg);
return false;
}
-
- clearWallpaperComponentLocked();
- mWallpaperComponent = componentName;
- mWallpaperConnection = newConn;
- mLastDiedTime = SystemClock.uptimeMillis();
+ if (wallpaper.userId == mCurrentUserId && mLastWallpaper != null) {
+ detachWallpaperLocked(mLastWallpaper);
+ }
+ wallpaper.wallpaperComponent = componentName;
+ wallpaper.connection = newConn;
+ wallpaper.lastDiedTime = SystemClock.uptimeMillis();
try {
- if (DEBUG) Slog.v(TAG, "Adding window token: " + newConn.mToken);
- mIWindowManager.addWindowToken(newConn.mToken,
- WindowManager.LayoutParams.TYPE_WALLPAPER);
+ if (wallpaper.userId == mCurrentUserId) {
+ if (DEBUG)
+ Slog.v(TAG, "Adding window token: " + newConn.mToken);
+ mIWindowManager.addWindowToken(newConn.mToken,
+ WindowManager.LayoutParams.TYPE_WALLPAPER);
+ mLastWallpaper = wallpaper;
+ }
} catch (RemoteException e) {
}
-
} catch (PackageManager.NameNotFoundException e) {
String msg = "Unknown component " + componentName;
if (fromUser) {
@@ -640,54 +797,58 @@
}
return true;
}
-
- void clearWallpaperComponentLocked() {
- mWallpaperComponent = null;
- if (mWallpaperConnection != null) {
- if (mWallpaperConnection.mEngine != null) {
+
+ void detachWallpaperLocked(WallpaperData wallpaper) {
+ if (wallpaper.connection != null) {
+ if (wallpaper.connection.mEngine != null) {
try {
- mWallpaperConnection.mEngine.destroy();
+ wallpaper.connection.mEngine.destroy();
} catch (RemoteException e) {
}
}
- mContext.unbindService(mWallpaperConnection);
+ mContext.unbindService(wallpaper.connection);
try {
- if (DEBUG) Slog.v(TAG, "Removing window token: "
- + mWallpaperConnection.mToken);
- mIWindowManager.removeWindowToken(mWallpaperConnection.mToken);
+ if (DEBUG)
+ Slog.v(TAG, "Removing window token: " + wallpaper.connection.mToken);
+ mIWindowManager.removeWindowToken(wallpaper.connection.mToken);
} catch (RemoteException e) {
}
- mWallpaperConnection.mService = null;
- mWallpaperConnection.mEngine = null;
- mWallpaperConnection = null;
+ wallpaper.connection.mService = null;
+ wallpaper.connection.mEngine = null;
+ wallpaper.connection = null;
}
}
-
- void attachServiceLocked(WallpaperConnection conn) {
+
+ void clearWallpaperComponentLocked(WallpaperData wallpaper) {
+ wallpaper.wallpaperComponent = null;
+ detachWallpaperLocked(wallpaper);
+ }
+
+ void attachServiceLocked(WallpaperConnection conn, WallpaperData wallpaper) {
try {
conn.mService.attach(conn, conn.mToken,
WindowManager.LayoutParams.TYPE_WALLPAPER, false,
- mWidth, mHeight);
+ wallpaper.width, wallpaper.height);
} catch (RemoteException e) {
Slog.w(TAG, "Failed attaching wallpaper; clearing", e);
- if (!mWallpaperUpdating) {
- bindWallpaperComponentLocked(null, false, false);
+ if (!wallpaper.wallpaperUpdating) {
+ bindWallpaperComponentLocked(null, false, false, wallpaper);
}
}
}
-
- private void notifyCallbacksLocked() {
- final int n = mCallbacks.beginBroadcast();
+
+ private void notifyCallbacksLocked(WallpaperData wallpaper) {
+ final int n = wallpaper.callbacks.beginBroadcast();
for (int i = 0; i < n; i++) {
try {
- mCallbacks.getBroadcastItem(i).onWallpaperChanged();
+ wallpaper.callbacks.getBroadcastItem(i).onWallpaperChanged();
} catch (RemoteException e) {
// The RemoteCallbackList will take care of removing
// the dead object for us.
}
}
- mCallbacks.finishBroadcast();
+ wallpaper.callbacks.finishBroadcast();
final Intent intent = new Intent(Intent.ACTION_WALLPAPER_CHANGED);
mContext.sendBroadcast(intent);
}
@@ -699,13 +860,13 @@
}
}
- private static JournaledFile makeJournaledFile() {
- final String base = "/data/system/wallpaper_info.xml";
+ private static JournaledFile makeJournaledFile(int userId) {
+ final String base = "/data/system/users/" + userId + "/" + WALLPAPER_INFO;
return new JournaledFile(new File(base), new File(base + ".tmp"));
}
- private void saveSettingsLocked() {
- JournaledFile journal = makeJournaledFile();
+ private void saveSettingsLocked(WallpaperData wallpaper) {
+ JournaledFile journal = makeJournaledFile(wallpaper.userId);
FileOutputStream stream = null;
try {
stream = new FileOutputStream(journal.chooseForWrite(), false);
@@ -714,13 +875,13 @@
out.startDocument(null, true);
out.startTag(null, "wp");
- out.attribute(null, "width", Integer.toString(mWidth));
- out.attribute(null, "height", Integer.toString(mHeight));
- out.attribute(null, "name", mName);
- if (mWallpaperComponent != null &&
- !mWallpaperComponent.equals(mImageWallpaperComponent)) {
+ out.attribute(null, "width", Integer.toString(wallpaper.width));
+ out.attribute(null, "height", Integer.toString(wallpaper.height));
+ out.attribute(null, "name", wallpaper.name);
+ if (wallpaper.wallpaperComponent != null
+ && !wallpaper.wallpaperComponent.equals(wallpaper.imageWallpaperComponent)) {
out.attribute(null, "component",
- mWallpaperComponent.flattenToShortString());
+ wallpaper.wallpaperComponent.flattenToShortString());
}
out.endTag(null, "wp");
@@ -739,12 +900,34 @@
}
}
- private void loadSettingsLocked() {
+ private void migrateFromOld() {
+ File oldWallpaper = new File(WallpaperBackupHelper.WALLPAPER_IMAGE_KEY);
+ File oldInfo = new File(WallpaperBackupHelper.WALLPAPER_INFO_KEY);
+ if (oldWallpaper.exists()) {
+ File newWallpaper = new File(getWallpaperDir(0), WALLPAPER);
+ oldWallpaper.renameTo(newWallpaper);
+ }
+ if (oldInfo.exists()) {
+ File newInfo = new File(getWallpaperDir(0), WALLPAPER_INFO);
+ oldInfo.renameTo(newInfo);
+ }
+ }
+
+ private void loadSettingsLocked(int userId) {
if (DEBUG) Slog.v(TAG, "loadSettingsLocked");
- JournaledFile journal = makeJournaledFile();
+ JournaledFile journal = makeJournaledFile(userId);
FileInputStream stream = null;
File file = journal.chooseForRead();
+ if (!file.exists()) {
+ // This should only happen one time, when upgrading from a legacy system
+ migrateFromOld();
+ }
+ WallpaperData wallpaper = mWallpaperMap.get(userId);
+ if (wallpaper == null) {
+ wallpaper = new WallpaperData(userId);
+ mWallpaperMap.put(userId, wallpaper);
+ }
boolean success = false;
try {
stream = new FileInputStream(file);
@@ -757,23 +940,26 @@
if (type == XmlPullParser.START_TAG) {
String tag = parser.getName();
if ("wp".equals(tag)) {
- mWidth = Integer.parseInt(parser.getAttributeValue(null, "width"));
- mHeight = Integer.parseInt(parser.getAttributeValue(null, "height"));
- mName = parser.getAttributeValue(null, "name");
+ wallpaper.width = Integer.parseInt(parser.getAttributeValue(null, "width"));
+ wallpaper.height = Integer.parseInt(parser
+ .getAttributeValue(null, "height"));
+ wallpaper.name = parser.getAttributeValue(null, "name");
String comp = parser.getAttributeValue(null, "component");
- mNextWallpaperComponent = comp != null
+ wallpaper.nextWallpaperComponent = comp != null
? ComponentName.unflattenFromString(comp)
: null;
- if (mNextWallpaperComponent == null ||
- "android".equals(mNextWallpaperComponent.getPackageName())) {
- mNextWallpaperComponent = mImageWallpaperComponent;
+ if (wallpaper.nextWallpaperComponent == null
+ || "android".equals(wallpaper.nextWallpaperComponent
+ .getPackageName())) {
+ wallpaper.nextWallpaperComponent = wallpaper.imageWallpaperComponent;
}
if (DEBUG) {
- Slog.v(TAG, "mWidth:" + mWidth);
- Slog.v(TAG, "mHeight:" + mHeight);
- Slog.v(TAG, "mName:" + mName);
- Slog.v(TAG, "mNextWallpaperComponent:" + mNextWallpaperComponent);
+ Slog.v(TAG, "mWidth:" + wallpaper.width);
+ Slog.v(TAG, "mHeight:" + wallpaper.height);
+ Slog.v(TAG, "mName:" + wallpaper.name);
+ Slog.v(TAG, "mNextWallpaperComponent:"
+ + wallpaper.nextWallpaperComponent);
}
}
}
@@ -799,70 +985,75 @@
}
if (!success) {
- mWidth = -1;
- mHeight = -1;
- mName = "";
+ wallpaper.width = -1;
+ wallpaper.height = -1;
+ wallpaper.name = "";
}
// We always want to have some reasonable width hint.
WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
Display d = wm.getDefaultDisplay();
int baseSize = d.getMaximumSizeDimension();
- if (mWidth < baseSize) {
- mWidth = baseSize;
+ if (wallpaper.width < baseSize) {
+ wallpaper.width = baseSize;
}
- if (mHeight < baseSize) {
- mHeight = baseSize;
+ if (wallpaper.height < baseSize) {
+ wallpaper.height = baseSize;
}
}
// Called by SystemBackupAgent after files are restored to disk.
void settingsRestored() {
+ // TODO: If necessary, make it work for secondary users as well. This currently assumes
+ // restores only to the primary user
if (DEBUG) Slog.v(TAG, "settingsRestored");
-
+ WallpaperData wallpaper = null;
boolean success = false;
synchronized (mLock) {
- loadSettingsLocked();
- if (mNextWallpaperComponent != null &&
- !mNextWallpaperComponent.equals(mImageWallpaperComponent)) {
- if (!bindWallpaperComponentLocked(mNextWallpaperComponent, false, false)) {
+ loadSettingsLocked(0);
+ wallpaper = mWallpaperMap.get(0);
+ if (wallpaper.nextWallpaperComponent != null
+ && !wallpaper.nextWallpaperComponent.equals(wallpaper.imageWallpaperComponent)) {
+ if (!bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, false, false,
+ wallpaper)) {
// No such live wallpaper or other failure; fall back to the default
// live wallpaper (since the profile being restored indicated that the
// user had selected a live rather than static one).
- bindWallpaperComponentLocked(null, false, false);
+ bindWallpaperComponentLocked(null, false, false, wallpaper);
}
success = true;
} else {
// If there's a wallpaper name, we use that. If that can't be loaded, then we
// use the default.
- if ("".equals(mName)) {
+ if ("".equals(wallpaper.name)) {
if (DEBUG) Slog.v(TAG, "settingsRestored: name is empty");
success = true;
} else {
if (DEBUG) Slog.v(TAG, "settingsRestored: attempting to restore named resource");
- success = restoreNamedResourceLocked();
+ success = restoreNamedResourceLocked(wallpaper);
}
if (DEBUG) Slog.v(TAG, "settingsRestored: success=" + success);
if (success) {
- bindWallpaperComponentLocked(mNextWallpaperComponent, false, false);
+ bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, false, false,
+ wallpaper);
}
}
}
if (!success) {
- Slog.e(TAG, "Failed to restore wallpaper: '" + mName + "'");
- mName = "";
- WALLPAPER_FILE.delete();
+ Slog.e(TAG, "Failed to restore wallpaper: '" + wallpaper.name + "'");
+ wallpaper.name = "";
+ getWallpaperDir(0).delete();
}
synchronized (mLock) {
- saveSettingsLocked();
+ saveSettingsLocked(wallpaper);
}
}
- boolean restoreNamedResourceLocked() {
- if (mName.length() > 4 && "res:".equals(mName.substring(0, 4))) {
- String resName = mName.substring(4);
+ boolean restoreNamedResourceLocked(WallpaperData wallpaper) {
+ if (wallpaper.name.length() > 4 && "res:".equals(wallpaper.name.substring(0, 4))) {
+ String resName = wallpaper.name.substring(4);
String pkg = null;
int colon = resName.indexOf(':');
@@ -896,10 +1087,10 @@
}
res = r.openRawResource(resId);
- if (WALLPAPER_FILE.exists()) {
- WALLPAPER_FILE.delete();
+ if (wallpaper.wallpaperFile.exists()) {
+ wallpaper.wallpaperFile.delete();
}
- fos = new FileOutputStream(WALLPAPER_FILE);
+ fos = new FileOutputStream(wallpaper.wallpaperFile);
byte[] buffer = new byte[32768];
int amt;
@@ -933,7 +1124,7 @@
}
return false;
}
-
+
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
@@ -947,20 +1138,35 @@
synchronized (mLock) {
pw.println("Current Wallpaper Service state:");
- pw.print(" mWidth="); pw.print(mWidth);
- pw.print(" mHeight="); pw.println(mHeight);
- pw.print(" mName="); pw.println(mName);
- pw.print(" mWallpaperComponent="); pw.println(mWallpaperComponent);
- if (mWallpaperConnection != null) {
- WallpaperConnection conn = mWallpaperConnection;
- pw.print(" Wallpaper connection ");
- pw.print(conn); pw.println(":");
- pw.print(" mInfo.component="); pw.println(conn.mInfo.getComponent());
- pw.print(" mToken="); pw.println(conn.mToken);
- pw.print(" mService="); pw.println(conn.mService);
- pw.print(" mEngine="); pw.println(conn.mEngine);
- pw.print(" mLastDiedTime=");
- pw.println(mLastDiedTime - SystemClock.uptimeMillis());
+ for (int i = 0; i < mWallpaperMap.size(); i++) {
+ WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+ pw.println(" User " + wallpaper.userId + ":");
+ pw.print(" mWidth=");
+ pw.print(wallpaper.width);
+ pw.print(" mHeight=");
+ pw.println(wallpaper.height);
+ pw.print(" mName=");
+ pw.println(wallpaper.name);
+ pw.print(" mWallpaperComponent=");
+ pw.println(wallpaper.wallpaperComponent);
+ if (wallpaper.connection != null) {
+ WallpaperConnection conn = wallpaper.connection;
+ pw.print(" Wallpaper connection ");
+ pw.print(conn);
+ pw.println(":");
+ if (conn.mInfo != null) {
+ pw.print(" mInfo.component=");
+ pw.println(conn.mInfo.getComponent());
+ }
+ pw.print(" mToken=");
+ pw.println(conn.mToken);
+ pw.print(" mService=");
+ pw.println(conn.mService);
+ pw.print(" mEngine=");
+ pw.println(conn.mEngine);
+ pw.print(" mLastDiedTime=");
+ pw.println(wallpaper.lastDiedTime - SystemClock.uptimeMillis());
+ }
}
}
}
diff --git a/services/java/com/android/server/WiredAccessoryObserver.java b/services/java/com/android/server/WiredAccessoryObserver.java
index 6a63eac..326b940 100644
--- a/services/java/com/android/server/WiredAccessoryObserver.java
+++ b/services/java/com/android/server/WiredAccessoryObserver.java
@@ -191,8 +191,12 @@
mHeadsetState = headsetState;
if (headsetState == 0) {
- Intent intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
- mContext.sendBroadcast(intent);
+ if (mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_sendAudioBecomingNoisy)) {
+ Intent intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
+ mContext.sendBroadcast(intent);
+ }
+
// It can take hundreds of ms flush the audio pipeline after
// apps pause audio playback, but audio route changes are
// immediate, so delay the route change by 1000ms.
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index 8bda755..586a67e 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -143,6 +143,8 @@
private final SecurityPolicy mSecurityPolicy;
+ private Service mUiAutomationService;
+
/**
* Handler for delayed event dispatch.
*/
@@ -494,19 +496,15 @@
}
}
// Hook the automation service up.
- Service service = new Service(componentName, accessibilityServiceInfo, true);
- service.onServiceConnected(componentName, listener.asBinder());
+ mUiAutomationService = new Service(componentName, accessibilityServiceInfo, true);
+ mUiAutomationService.onServiceConnected(componentName, listener.asBinder());
}
public void unregisterUiTestAutomationService(IEventListener listener) {
synchronized (mLock) {
- final int serviceCount = mServices.size();
- for (int i = 0; i < serviceCount; i++) {
- Service service = mServices.get(i);
- if (service.mServiceInterface == listener && service.mIsAutomation) {
- // Automation service is not bound, so pretend it died to perform clean up.
- service.binderDied();
- }
+ // Automation service is not bound, so pretend it died to perform clean up.
+ if (mUiAutomationService != null) {
+ mUiAutomationService.binderDied();
}
}
}
@@ -741,7 +739,10 @@
* Manages services by starting enabled ones and stopping disabled ones.
*/
private void manageServicesLocked() {
- unbindAutomationService();
+ // While the UI automation service is running it takes over.
+ if (mUiAutomationService != null) {
+ return;
+ }
populateEnabledServicesLocked(mEnabledServices);
final int enabledInstalledServicesCount = updateServicesStateLocked(mInstalledServices,
mEnabledServices);
@@ -769,21 +770,6 @@
}
/**
- * Unbinds the automation service if such is running.
- */
- private void unbindAutomationService() {
- List<Service> runningServices = mServices;
- int runningServiceCount = mServices.size();
- for (int i = 0; i < runningServiceCount; i++) {
- Service service = runningServices.get(i);
- if (service.mIsAutomation) {
- service.unbind();
- return;
- }
- }
- }
-
- /**
* Populates a list with the {@link ComponentName}s of all enabled
* {@link AccessibilityService}s.
*
@@ -1248,6 +1234,7 @@
// We no longer have an automation service, so restore
// the state based on values in the settings database.
if (mIsAutomation) {
+ mUiAutomationService = null;
handleAccessibilityEnabledSettingChangedLocked();
}
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index e6a1e68..7bf26cc 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -38,7 +38,6 @@
import android.app.ApplicationErrorReport;
import android.app.Dialog;
import android.app.IActivityController;
-import android.app.IActivityWatcher;
import android.app.IApplicationThread;
import android.app.IInstrumentationWatcher;
import android.app.INotificationManager;
@@ -50,6 +49,7 @@
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
+import android.app.WallpaperManager;
import android.app.backup.IBackupManager;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
@@ -138,6 +138,7 @@
import java.lang.IllegalStateException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
@@ -268,7 +269,14 @@
static final String[] EMPTY_STRING_ARRAY = new String[0];
public ActivityStack mMainStack;
-
+
+ private final boolean mHeadless;
+
+ // Whether we should show our dialogs (ANR, crash, etc) or just perform their
+ // default actuion automatically. Important for devices without direct input
+ // devices.
+ private boolean mShowDialogs = true;
+
/**
* Description of a request to start a new activity, which has been held
* due to app switches being disabled.
@@ -834,7 +842,7 @@
info.activityInfo.applicationInfo, true,
r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
"broadcast", r.curComponent,
- (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
+ (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false))
== null) {
// Ah, this recipient is unavailable. Finish it if necessary,
// and mark the broadcast record as ready for the next.
@@ -1135,6 +1143,17 @@
final ProcessMap<ProcessRecord> mProcessNames = new ProcessMap<ProcessRecord>();
/**
+ * The currently running isolated processes.
+ */
+ final SparseArray<ProcessRecord> mIsolatedProcesses = new SparseArray<ProcessRecord>();
+
+ /**
+ * Counter for assigning isolated process uids, to avoid frequently reusing the
+ * same ones.
+ */
+ int mNextIsolatedProcessUid = 0;
+
+ /**
* The currently running heavy-weight process, if any.
*/
ProcessRecord mHeavyWeightProcess = null;
@@ -1350,24 +1369,6 @@
*/
final ArrayList mCancelledThumbnails = new ArrayList();
- /**
- * All of the currently running global content providers. Keys are a
- * string containing the provider name and values are a
- * ContentProviderRecord object containing the data about it. Note
- * that a single provider may be published under multiple names, so
- * there may be multiple entries here for a single one in mProvidersByClass.
- */
- final HashMap<String, ContentProviderRecord> mProvidersByName
- = new HashMap<String, ContentProviderRecord>();
-
- /**
- * All of the currently running global content providers. Keys are a
- * string containing the provider's implementation class and values are a
- * ContentProviderRecord object containing the data about it.
- */
- final HashMap<ComponentName, ContentProviderRecord> mProvidersByClass
- = new HashMap<ComponentName, ContentProviderRecord>();
-
final ProviderMap mProviderMap = new ProviderMap();
/**
@@ -1548,9 +1549,6 @@
int mProfileType = 0;
boolean mAutoStopProfiler = false;
- final RemoteCallbackList<IActivityWatcher> mWatchers
- = new RemoteCallbackList<IActivityWatcher>();
-
final RemoteCallbackList<IProcessObserver> mProcessObservers
= new RemoteCallbackList<IProcessObserver>();
@@ -1668,7 +1666,7 @@
return;
}
AppErrorResult res = (AppErrorResult) data.get("result");
- if (!mSleeping && !mShuttingDown) {
+ if (mShowDialogs && !mSleeping && !mShuttingDown) {
Dialog d = new AppErrorDialog(mContext, res, proc);
d.show();
proc.crashDialog = d;
@@ -1720,7 +1718,7 @@
return;
}
AppErrorResult res = (AppErrorResult) data.get("result");
- if (!mSleeping && !mShuttingDown) {
+ if (mShowDialogs && !mSleeping && !mShuttingDown) {
Dialog d = new StrictModeViolationDialog(mContext, res, proc);
d.show();
proc.crashDialog = d;
@@ -1842,16 +1840,22 @@
}
} break;
case SHOW_UID_ERROR_MSG: {
- // XXX This is a temporary dialog, no need to localize.
- AlertDialog d = new BaseErrorDialog(mContext);
- d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
- d.setCancelable(false);
- d.setTitle("System UIDs Inconsistent");
- d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
- d.setButton(DialogInterface.BUTTON_POSITIVE, "I'm Feeling Lucky",
- mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
- mUidAlert = d;
- d.show();
+ String title = "System UIDs Inconsistent";
+ String text = "UIDs on the system are inconsistent, you need to wipe your"
+ + " data partition or your device will be unstable.";
+ Log.e(TAG, title + ": " + text);
+ if (mShowDialogs) {
+ // XXX This is a temporary dialog, no need to localize.
+ AlertDialog d = new BaseErrorDialog(mContext);
+ d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
+ d.setCancelable(false);
+ d.setTitle(title);
+ d.setMessage(text);
+ d.setButton(DialogInterface.BUTTON_POSITIVE, "I'm Feeling Lucky",
+ mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
+ mUidAlert = d;
+ d.show();
+ }
} break;
case IM_FEELING_LUCKY_MSG: {
if (mUidAlert != null) {
@@ -2081,7 +2085,7 @@
try {
ActivityManagerService m = mSelf;
- ServiceManager.addService("activity", m);
+ ServiceManager.addService("activity", m, true);
ServiceManager.addService("meminfo", new MemBinder(m));
ServiceManager.addService("gfxinfo", new GraphicsBinder(m));
ServiceManager.addService("dbinfo", new DbBinder(m));
@@ -2098,11 +2102,11 @@
synchronized (mSelf) {
ProcessRecord app = mSelf.newProcessRecordLocked(
mSystemThread.getApplicationThread(), info,
- info.processName);
+ info.processName, false);
app.persistent = true;
app.pid = MY_PID;
app.maxAdj = ProcessList.SYSTEM_ADJ;
- mSelf.mProcessNames.put(app.processName, app.info.uid, app);
+ mSelf.mProcessNames.put(app.processName, app.uid, app);
synchronized (mSelf.mPidsSelfLocked) {
mSelf.mPidsSelfLocked.put(app.pid, app);
}
@@ -2299,6 +2303,7 @@
mUsageStatsService = new UsageStatsService(new File(
systemDir, "usagestats").toString());
+ mHeadless = "1".equals(SystemProperties.get("ro.config.headless", "0"));
GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
@@ -2620,8 +2625,15 @@
final ProcessRecord startProcessLocked(String processName,
ApplicationInfo info, boolean knownToBeDead, int intentFlags,
- String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
- ProcessRecord app = getProcessRecordLocked(processName, info.uid);
+ String hostingType, ComponentName hostingName, boolean allowWhileBooting,
+ boolean isolated) {
+ ProcessRecord app;
+ if (!isolated) {
+ app = getProcessRecordLocked(processName, info.uid);
+ } else {
+ // If this is an isolated process, it can't re-use an existing process.
+ app = null;
+ }
// We don't have to do anything more if:
// (1) There is an existing application record; and
// (2) The caller doesn't think it is dead, OR there is no thread
@@ -2650,36 +2662,46 @@
String hostingNameStr = hostingName != null
? hostingName.flattenToShortString() : null;
-
- if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
- // If we are in the background, then check to see if this process
- // is bad. If so, we will just silently fail.
- if (mBadProcesses.get(info.processName, info.uid) != null) {
- if (DEBUG_PROCESSES) Slog.v(TAG, "Bad process: " + info.uid
+
+ if (!isolated) {
+ if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
+ // If we are in the background, then check to see if this process
+ // is bad. If so, we will just silently fail.
+ if (mBadProcesses.get(info.processName, info.uid) != null) {
+ if (DEBUG_PROCESSES) Slog.v(TAG, "Bad process: " + info.uid
+ + "/" + info.processName);
+ return null;
+ }
+ } else {
+ // When the user is explicitly starting a process, then clear its
+ // crash count so that we won't make it bad until they see at
+ // least one crash dialog again, and make the process good again
+ // if it had been bad.
+ if (DEBUG_PROCESSES) Slog.v(TAG, "Clearing bad process: " + info.uid
+ "/" + info.processName);
- return null;
- }
- } else {
- // When the user is explicitly starting a process, then clear its
- // crash count so that we won't make it bad until they see at
- // least one crash dialog again, and make the process good again
- // if it had been bad.
- if (DEBUG_PROCESSES) Slog.v(TAG, "Clearing bad process: " + info.uid
- + "/" + info.processName);
- mProcessCrashTimes.remove(info.processName, info.uid);
- if (mBadProcesses.get(info.processName, info.uid) != null) {
- EventLog.writeEvent(EventLogTags.AM_PROC_GOOD, info.uid,
- info.processName);
- mBadProcesses.remove(info.processName, info.uid);
- if (app != null) {
- app.bad = false;
+ mProcessCrashTimes.remove(info.processName, info.uid);
+ if (mBadProcesses.get(info.processName, info.uid) != null) {
+ EventLog.writeEvent(EventLogTags.AM_PROC_GOOD, info.uid,
+ info.processName);
+ mBadProcesses.remove(info.processName, info.uid);
+ if (app != null) {
+ app.bad = false;
+ }
}
}
}
-
+
if (app == null) {
- app = newProcessRecordLocked(null, info, processName);
- mProcessNames.put(processName, info.uid, app);
+ app = newProcessRecordLocked(null, info, processName, isolated);
+ if (app == null) {
+ Slog.w(TAG, "Failed making new process record for "
+ + processName + "/" + info.uid + " isolated=" + isolated);
+ return null;
+ }
+ mProcessNames.put(processName, app.uid, app);
+ if (isolated) {
+ mIsolatedProcesses.put(app.uid, app);
+ }
} else {
// If this is a new package in the process, add the package to the list
app.addPackage(info.packageName);
@@ -2725,14 +2747,16 @@
mProcDeaths[0] = 0;
try {
- int uid = app.info.uid;
+ int uid = app.uid;
int[] gids = null;
- try {
- gids = mContext.getPackageManager().getPackageGids(
- app.info.packageName);
- } catch (PackageManager.NameNotFoundException e) {
- Slog.w(TAG, "Unable to retrieve gids", e);
+ if (!app.isolated) {
+ try {
+ gids = mContext.getPackageManager().getPackageGids(
+ app.info.packageName);
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.w(TAG, "Unable to retrieve gids", e);
+ }
}
if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
@@ -2839,6 +2863,13 @@
}
boolean startHomeActivityLocked(int userId) {
+ if (mHeadless) {
+ // Added because none of the other calls to ensureBootCompleted seem to fire
+ // when running headless.
+ ensureBootCompleted();
+ return false;
+ }
+
if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
&& mTopAction == null) {
// We are running in factory test mode, but unable to find
@@ -2933,37 +2964,52 @@
return mCompatModePackages.compatibilityInfoForPackageLocked(ai);
}
+ void enforceNotIsolatedCaller(String caller) {
+ if (UserId.isIsolated(Binder.getCallingUid())) {
+ throw new SecurityException("Isolated process not allowed to call " + caller);
+ }
+ }
+
public int getFrontActivityScreenCompatMode() {
+ enforceNotIsolatedCaller("getFrontActivityScreenCompatMode");
synchronized (this) {
return mCompatModePackages.getFrontActivityScreenCompatModeLocked();
}
}
public void setFrontActivityScreenCompatMode(int mode) {
+ enforceCallingPermission(android.Manifest.permission.SET_SCREEN_COMPATIBILITY,
+ "setFrontActivityScreenCompatMode");
synchronized (this) {
mCompatModePackages.setFrontActivityScreenCompatModeLocked(mode);
}
}
public int getPackageScreenCompatMode(String packageName) {
+ enforceNotIsolatedCaller("getPackageScreenCompatMode");
synchronized (this) {
return mCompatModePackages.getPackageScreenCompatModeLocked(packageName);
}
}
public void setPackageScreenCompatMode(String packageName, int mode) {
+ enforceCallingPermission(android.Manifest.permission.SET_SCREEN_COMPATIBILITY,
+ "setPackageScreenCompatMode");
synchronized (this) {
mCompatModePackages.setPackageScreenCompatModeLocked(packageName, mode);
}
}
public boolean getPackageAskScreenCompat(String packageName) {
+ enforceNotIsolatedCaller("getPackageAskScreenCompat");
synchronized (this) {
return mCompatModePackages.getPackageAskCompatModeLocked(packageName);
}
}
public void setPackageAskScreenCompat(String packageName, boolean ask) {
+ enforceCallingPermission(android.Manifest.permission.SET_SCREEN_COMPATIBILITY,
+ "setPackageAskScreenCompat");
synchronized (this) {
mCompatModePackages.setPackageAskCompatModeLocked(packageName, ask);
}
@@ -2974,19 +3020,6 @@
final int identHash = System.identityHashCode(r);
updateUsageStats(r, true);
-
- int i = mWatchers.beginBroadcast();
- while (i > 0) {
- i--;
- IActivityWatcher w = mWatchers.getBroadcastItem(i);
- if (w != null) {
- try {
- w.activityResuming(identHash);
- } catch (RemoteException e) {
- }
- }
- }
- mWatchers.finishBroadcast();
}
private void dispatchForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) {
@@ -3038,6 +3071,7 @@
int grantedMode, IBinder resultTo,
String resultWho, int requestCode, boolean onlyIfNeeded, boolean debug,
String profileFile, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {
+ enforceNotIsolatedCaller("startActivity");
int userId = 0;
if (intent.getCategories() != null && intent.getCategories().contains(Intent.CATEGORY_HOME)) {
// Requesting home, set the identity to the current user
@@ -3062,6 +3096,7 @@
int grantedMode, IBinder resultTo,
String resultWho, int requestCode, boolean onlyIfNeeded, boolean debug,
String profileFile, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {
+ enforceNotIsolatedCaller("startActivityAndWait");
WaitResult res = new WaitResult();
int userId = Binder.getOrigCallingUser();
mMainStack.startActivityMayWait(caller, -1, intent, resolvedType,
@@ -3076,6 +3111,7 @@
int grantedMode, IBinder resultTo,
String resultWho, int requestCode, boolean onlyIfNeeded,
boolean debug, Configuration config) {
+ enforceNotIsolatedCaller("startActivityWithConfig");
int ret = mMainStack.startActivityMayWait(caller, -1, intent, resolvedType,
grantedUriPermissions, grantedMode, resultTo, resultWho,
requestCode, onlyIfNeeded,
@@ -3087,6 +3123,7 @@
IntentSender intent, Intent fillInIntent, String resolvedType,
IBinder resultTo, String resultWho, int requestCode,
int flagsMask, int flagsValues) {
+ enforceNotIsolatedCaller("startActivityIntentSender");
// Refuse possible leaked file descriptors
if (fillInIntent != null && fillInIntent.hasFileDescriptors()) {
throw new IllegalArgumentException("File descriptors passed in Intent");
@@ -3228,6 +3265,7 @@
public final int startActivities(IApplicationThread caller,
Intent[] intents, String[] resolvedTypes, IBinder resultTo) {
+ enforceNotIsolatedCaller("startActivities");
int ret = mMainStack.startActivities(caller, -1, intents, resolvedTypes, resultTo,
Binder.getOrigCallingUser());
return ret;
@@ -3404,7 +3442,7 @@
synchronized (mPidsSelfLocked) {
for (int i=0; i<mPidsSelfLocked.size(); i++) {
ProcessRecord p = mPidsSelfLocked.valueAt(i);
- if (p.info.uid != uid) {
+ if (p.uid != uid) {
continue;
}
if (p.pid == initialPid) {
@@ -3520,13 +3558,7 @@
}
// Just in case...
- if (mMainStack.mPausingActivity != null && mMainStack.mPausingActivity.app == app) {
- if (DEBUG_PAUSE) Slog.v(TAG, "App died while pausing: " +mMainStack.mPausingActivity);
- mMainStack.mPausingActivity = null;
- }
- if (mMainStack.mLastPausedActivity != null && mMainStack.mLastPausedActivity.app == app) {
- mMainStack.mLastPausedActivity = null;
- }
+ mMainStack.appDiedLocked(app);
// Remove this application's activities from active lists.
mMainStack.removeHistoryRecordsForAppLocked(app);
@@ -3995,6 +4027,7 @@
public boolean clearApplicationUserData(final String packageName,
final IPackageDataObserver observer, final int userId) {
+ enforceNotIsolatedCaller("clearApplicationUserData");
int uid = Binder.getCallingUid();
int pid = Binder.getCallingPid();
long callingId = Binder.clearCallingIdentity();
@@ -4183,6 +4216,7 @@
}
public void closeSystemDialogs(String reason) {
+ enforceNotIsolatedCaller("closeSystemDialogs");
Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
if (reason != null) {
@@ -4192,22 +4226,9 @@
final int uid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
synchronized (this) {
- int i = mWatchers.beginBroadcast();
- while (i > 0) {
- i--;
- IActivityWatcher w = mWatchers.getBroadcastItem(i);
- if (w != null) {
- try {
- w.closingSystemDialogs(reason);
- } catch (RemoteException e) {
- }
- }
- }
- mWatchers.finishBroadcast();
-
mWindowManager.closeSystemDialogs(reason);
- for (i=mMainStack.mHistory.size()-1; i>=0; i--) {
+ for (int i=mMainStack.mHistory.size()-1; i>=0; i--) {
ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
r.stack.finishActivityLocked(r, i,
@@ -4223,6 +4244,7 @@
public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids)
throws RemoteException {
+ enforceNotIsolatedCaller("getProcessMemoryInfo");
Debug.MemoryInfo[] infos = new Debug.MemoryInfo[pids.length];
for (int i=pids.length-1; i>=0; i--) {
infos[i] = new Debug.MemoryInfo();
@@ -4232,6 +4254,7 @@
}
public long[] getProcessPss(int[] pids) throws RemoteException {
+ enforceNotIsolatedCaller("getProcessPss");
long[] pss = new long[pids.length];
for (int i=pids.length-1; i>=0; i--) {
pss[i] = Debug.getPss(pids[i]);
@@ -4394,6 +4417,7 @@
service.app.removed = true;
}
service.app = null;
+ service.isolatedProc = null;
services.add(service);
}
}
@@ -4404,7 +4428,7 @@
}
ArrayList<ContentProviderRecord> providers = new ArrayList<ContentProviderRecord>();
- for (ContentProviderRecord provider : mProvidersByClass.values()) {
+ for (ContentProviderRecord provider : mProviderMap.getProvidersByClass(-1).values()) {
if (provider.info.packageName.equals(name)
&& (provider.proc == null || evenPersistent || !provider.proc.persistent)) {
if (!doit) {
@@ -4439,12 +4463,13 @@
private final boolean removeProcessLocked(ProcessRecord app,
boolean callerWillRestart, boolean allowRestart, String reason) {
final String name = app.processName;
- final int uid = app.info.uid;
+ final int uid = app.uid;
if (DEBUG_PROCESSES) Slog.d(
TAG, "Force removing proc " + app.toShortString() + " (" + name
+ "/" + uid + ")");
mProcessNames.remove(name, uid);
+ mIsolatedProcesses.remove(app.uid);
if (mHeavyWeightProcess == app) {
mHeavyWeightProcess = null;
mHandler.sendEmptyMessage(CANCEL_HEAVY_NOTIFICATION_MSG);
@@ -4461,9 +4486,9 @@
mLruProcesses.remove(app);
Process.killProcessQuiet(pid);
- if (app.persistent) {
+ if (app.persistent && !app.isolated) {
if (!callerWillRestart) {
- addAppLocked(app.info);
+ addAppLocked(app.info, false);
} else {
needRestart = true;
}
@@ -4488,9 +4513,10 @@
if (gone) {
Slog.w(TAG, "Process " + app + " failed to attach");
- EventLog.writeEvent(EventLogTags.AM_PROCESS_START_TIMEOUT, pid, app.info.uid,
+ EventLog.writeEvent(EventLogTags.AM_PROCESS_START_TIMEOUT, pid, app.uid,
app.processName);
- mProcessNames.remove(app.processName, app.info.uid);
+ mProcessNames.remove(app.processName, app.uid);
+ mIsolatedProcesses.remove(app.uid);
if (mHeavyWeightProcess == app) {
mHeavyWeightProcess = null;
mHandler.sendEmptyMessage(CANCEL_HEAVY_NOTIFICATION_MSG);
@@ -4500,9 +4526,11 @@
// Take care of any services that are waiting for the process.
for (int i=0; i<mPendingServices.size(); i++) {
ServiceRecord sr = mPendingServices.get(i);
- if (app.info.uid == sr.appInfo.uid
- && app.processName.equals(sr.processName)) {
+ if ((app.uid == sr.appInfo.uid
+ && app.processName.equals(sr.processName))
+ || sr.isolatedProc == app) {
Slog.w(TAG, "Forcing bringing down service: " + sr);
+ sr.isolatedProc = null;
mPendingServices.remove(i);
i--;
bringDownServiceLocked(sr, true);
@@ -4683,10 +4711,12 @@
// See if the top visible activity is waiting to run in this process...
ActivityRecord hr = mMainStack.topRunningActivityLocked(null);
if (hr != null && normalMode) {
- if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
+ if (hr.app == null && app.uid == hr.info.applicationInfo.uid
&& processName.equals(hr.processName)) {
try {
- if (mMainStack.realStartActivityLocked(hr, app, true, true)) {
+ if (mHeadless) {
+ Slog.e(TAG, "Starting activities not supported on headless device: " + hr);
+ } else if (mMainStack.realStartActivityLocked(hr, app, true, true)) {
didSomething = true;
}
} catch (Exception e) {
@@ -4705,8 +4735,8 @@
try {
for (int i=0; i<mPendingServices.size(); i++) {
sr = mPendingServices.get(i);
- if (app.info.uid != sr.appInfo.uid
- || !processName.equals(sr.processName)) {
+ if (app != sr.isolatedProc && (app.uid != sr.appInfo.uid
+ || !processName.equals(sr.processName))) {
continue;
}
@@ -4733,7 +4763,7 @@
}
// Check whether the next backup agent is in this process...
- if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
+ if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.uid) {
if (DEBUG_BACKUP) Slog.v(TAG, "New app is backup target, launching agent for " + app);
ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
try {
@@ -4795,10 +4825,12 @@
}
public void showBootMessage(final CharSequence msg, final boolean always) {
+ enforceNotIsolatedCaller("showBootMessage");
mWindowManager.showBootMessage(msg, always);
}
public void dismissKeyguardOnNextActivity() {
+ enforceNotIsolatedCaller("dismissKeyguardOnNextActivity");
synchronized (this) {
mMainStack.dismissKeyguardOnNextActivityLocked();
}
@@ -4961,6 +4993,7 @@
public IIntentSender getIntentSender(int type,
String packageName, IBinder token, String resultWho,
int requestCode, Intent[] intents, String[] resolvedTypes, int flags) {
+ enforceNotIsolatedCaller("getIntentSender");
// Refuse possible leaked file descriptors
if (intents != null) {
if (intents.length < 1) {
@@ -5188,7 +5221,7 @@
synchronized (mPidsSelfLocked) {
ProcessRecord pr = mPidsSelfLocked.get(pid);
- if (pr == null) {
+ if (pr == null && isForeground) {
Slog.w(TAG, "setProcessForeground called on unknown pid: " + pid);
return;
}
@@ -5196,7 +5229,9 @@
if (oldToken != null) {
oldToken.token.unlinkToDeath(oldToken, 0);
mForegroundProcesses.remove(pid);
- pr.forcingToForeground = null;
+ if (pr != null) {
+ pr.forcingToForeground = null;
+ }
changed = true;
}
if (isForeground && token != null) {
@@ -5261,6 +5296,10 @@
if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID) {
return PackageManager.PERMISSION_GRANTED;
}
+ // Isolated processes don't get any permissions.
+ if (UserId.isIsolated(uid)) {
+ return PackageManager.PERMISSION_DENIED;
+ }
// If there is a uid that owns whatever is being accessed, it has
// blanket access to it regardless of the permissions it requires.
if (owningUid >= 0 && UserId.isSameApp(uid, owningUid)) {
@@ -5413,6 +5452,8 @@
}
public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
+ enforceNotIsolatedCaller("checkUriPermission");
+
// Another redirected-binder-call permissions check as in
// {@link checkComponentPermission}.
Identity tlsIdentity = sCallerIdentity.get();
@@ -5563,6 +5604,7 @@
public int checkGrantUriPermission(int callingUid, String targetPkg,
Uri uri, int modeFlags) {
+ enforceNotIsolatedCaller("checkGrantUriPermission");
synchronized(this) {
return checkGrantUriPermissionLocked(callingUid, targetPkg, uri, modeFlags);
}
@@ -5671,6 +5713,7 @@
public void grantUriPermission(IApplicationThread caller, String targetPkg,
Uri uri, int modeFlags) {
+ enforceNotIsolatedCaller("grantUriPermission");
synchronized(this) {
final ProcessRecord r = getRecordForAppLocked(caller);
if (r == null) {
@@ -5685,7 +5728,7 @@
throw new IllegalArgumentException("null uri");
}
- grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
+ grantUriPermissionLocked(r.uid, targetPkg, uri, modeFlags,
null);
}
}
@@ -5794,6 +5837,7 @@
public void revokeUriPermission(IApplicationThread caller, Uri uri,
int modeFlags) {
+ enforceNotIsolatedCaller("revokeUriPermission");
synchronized(this) {
final ProcessRecord r = getRecordForAppLocked(caller);
if (r == null) {
@@ -5816,8 +5860,7 @@
final String authority = uri.getAuthority();
ProviderInfo pi = null;
- ContentProviderRecord cpr = mProviderMap.getProviderByName(authority,
- UserId.getUserId(r.info.uid));
+ ContentProviderRecord cpr = mProviderMap.getProviderByName(authority, r.userId);
if (cpr != null) {
pi = cpr.info;
} else {
@@ -5833,12 +5876,13 @@
return;
}
- revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
+ revokeUriPermissionLocked(r.uid, uri, modeFlags);
}
}
@Override
public IBinder newUriPermissionOwner(String name) {
+ enforceNotIsolatedCaller("newUriPermissionOwner");
synchronized(this) {
UriPermissionOwner owner = new UriPermissionOwner(this, name);
return owner.getExternalTokenLocked();
@@ -6375,6 +6419,7 @@
* @return Returns true if the move completed, false if not.
*/
public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
+ enforceNotIsolatedCaller("moveActivityTaskToBack");
synchronized(this) {
final long origId = Binder.clearCallingIdentity();
int taskId = getTaskForActivityLocked(token, !nonRoot);
@@ -6428,29 +6473,6 @@
return -1;
}
- public void finishOtherInstances(IBinder token, ComponentName className) {
- synchronized(this) {
- final long origId = Binder.clearCallingIdentity();
-
- int N = mMainStack.mHistory.size();
- TaskRecord lastTask = null;
- for (int i=0; i<N; i++) {
- ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
- if (r.realActivity.equals(className)
- && r.appToken != token && lastTask != r.task) {
- if (r.stack.finishActivityLocked(r, i, Activity.RESULT_CANCELED,
- null, "others")) {
- i--;
- N--;
- }
- }
- lastTask = r.task;
- }
-
- Binder.restoreCallingIdentity(origId);
- }
- }
-
// =========================================================
// THUMBNAILS
// =========================================================
@@ -6537,13 +6559,13 @@
List<ProviderInfo> providers = null;
try {
providers = AppGlobals.getPackageManager().
- queryContentProviders(app.processName, app.info.uid,
+ queryContentProviders(app.processName, app.uid,
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
} catch (RemoteException ex) {
}
if (DEBUG_MU)
- Slog.v(TAG_MU, "generateApplicationProvidersLocked, app.info.uid = " + app.info.uid);
- int userId = UserId.getUserId(app.info.uid);
+ Slog.v(TAG_MU, "generateApplicationProvidersLocked, app.info.uid = " + app.uid);
+ int userId = app.userId;
if (providers != null) {
final int N = providers.size();
for (int i=0; i<N; i++) {
@@ -6569,7 +6591,7 @@
private final String checkContentProviderPermissionLocked(
ProviderInfo cpi, ProcessRecord r) {
final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
- final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
+ final int callingUid = (r != null) ? r.uid : Binder.getCallingUid();
if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
cpi.applicationInfo.uid, cpi.exported)
== PackageManager.PERMISSION_GRANTED) {
@@ -6685,7 +6707,7 @@
}
// First check if this content provider has been published...
- int userId = UserId.getUserId(r != null ? r.info.uid : Binder.getCallingUid());
+ int userId = UserId.getUserId(r != null ? r.uid : Binder.getCallingUid());
cpr = mProviderMap.getProviderByName(name, userId);
boolean providerRunning = cpr != null;
if (providerRunning) {
@@ -6820,7 +6842,7 @@
if (DEBUG_PROVIDER) {
RuntimeException e = new RuntimeException("here");
- Slog.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
+ Slog.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.uid
+ " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);
}
@@ -6854,7 +6876,7 @@
ProcessRecord proc = startProcessLocked(cpi.processName,
cpr.appInfo, false, 0, "content provider",
new ComponentName(cpi.applicationInfo.packageName,
- cpi.name), false);
+ cpi.name), false, false);
if (proc == null) {
Slog.w(TAG, "Unable to launch app "
+ cpi.applicationInfo.packageName + "/"
@@ -6907,6 +6929,7 @@
public final ContentProviderHolder getContentProvider(
IApplicationThread caller, String name) {
+ enforceNotIsolatedCaller("getContentProvider");
if (caller == null) {
String msg = "null IApplicationThread when getting content provider "
+ name;
@@ -6927,6 +6950,7 @@
* @param cpr
*/
public void removeContentProvider(IApplicationThread caller, String name) {
+ enforceNotIsolatedCaller("removeContentProvider");
synchronized (this) {
int userId = UserId.getUserId(Binder.getCallingUid());
ContentProviderRecord cpr = mProviderMap.getProviderByName(name, userId);
@@ -6989,10 +7013,11 @@
return;
}
+ enforceNotIsolatedCaller("publishContentProviders");
synchronized(this) {
final ProcessRecord r = getRecordForAppLocked(caller);
if (DEBUG_MU)
- Slog.v(TAG_MU, "ProcessRecord uid = " + r.info.uid);
+ Slog.v(TAG_MU, "ProcessRecord uid = " + r.uid);
if (r == null) {
throw new SecurityException(
"Unable to find app for caller " + caller
@@ -7076,6 +7101,7 @@
* src/com/android/cts/usespermissiondiffcertapp/AccessPermissionWithDiffSigTest.java
*/
public String getProviderMimeType(Uri uri) {
+ enforceNotIsolatedCaller("getProviderMimeType");
final String name = uri.getAuthority();
final long ident = Binder.clearCallingIdentity();
ContentProviderHolder holder = null;
@@ -7103,22 +7129,52 @@
// =========================================================
final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
- ApplicationInfo info, String customProcess) {
+ ApplicationInfo info, String customProcess, boolean isolated) {
String proc = customProcess != null ? customProcess : info.processName;
BatteryStatsImpl.Uid.Proc ps = null;
BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
+ int uid = info.uid;
+ if (isolated) {
+ int userId = UserId.getUserId(uid);
+ int stepsLeft = Process.LAST_ISOLATED_UID - Process.FIRST_ISOLATED_UID + 1;
+ uid = 0;
+ while (true) {
+ if (mNextIsolatedProcessUid < Process.FIRST_ISOLATED_UID
+ || mNextIsolatedProcessUid > Process.LAST_ISOLATED_UID) {
+ mNextIsolatedProcessUid = Process.FIRST_ISOLATED_UID;
+ }
+ uid = UserId.getUid(userId, mNextIsolatedProcessUid);
+ mNextIsolatedProcessUid++;
+ if (mIsolatedProcesses.indexOfKey(uid) < 0) {
+ // No process for this uid, use it.
+ break;
+ }
+ stepsLeft--;
+ if (stepsLeft <= 0) {
+ return null;
+ }
+ }
+ }
synchronized (stats) {
ps = stats.getProcessStatsLocked(info.uid, proc);
}
- return new ProcessRecord(ps, thread, info, proc);
+ return new ProcessRecord(ps, thread, info, proc, uid);
}
- final ProcessRecord addAppLocked(ApplicationInfo info) {
- ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
+ final ProcessRecord addAppLocked(ApplicationInfo info, boolean isolated) {
+ ProcessRecord app;
+ if (!isolated) {
+ app = getProcessRecordLocked(info.processName, info.uid);
+ } else {
+ app = null;
+ }
if (app == null) {
- app = newProcessRecordLocked(null, info, null);
- mProcessNames.put(info.processName, info.uid, app);
+ app = newProcessRecordLocked(null, info, null, isolated);
+ mProcessNames.put(info.processName, app.uid, app);
+ if (isolated) {
+ mIsolatedProcesses.put(app.uid, app);
+ }
updateLruProcessLocked(app, true, true);
}
@@ -7163,6 +7219,7 @@
}
public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
+ enforceNotIsolatedCaller("openContentUri");
String name = uri.getAuthority();
ContentProviderHolder cph = getContentProviderExternal(name);
ParcelFileDescriptor pfd = null;
@@ -7231,7 +7288,7 @@
mMainStack.stopIfSleepingLocked();
final long endTime = System.currentTimeMillis() + timeout;
while (mMainStack.mResumedActivity != null
- || mMainStack.mPausingActivity != null) {
+ || mMainStack.mPausingActivities.size() > 0) {
long delay = endTime - System.currentTimeMillis();
if (delay <= 0) {
Slog.w(TAG, "Activity manager shutdown timed out");
@@ -7415,24 +7472,18 @@
}
}
- public void registerActivityWatcher(IActivityWatcher watcher) {
- synchronized (this) {
- mWatchers.register(watcher);
- }
- }
-
- public void unregisterActivityWatcher(IActivityWatcher watcher) {
- synchronized (this) {
- mWatchers.unregister(watcher);
- }
- }
-
public void registerProcessObserver(IProcessObserver observer) {
- mProcessObservers.register(observer);
+ enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
+ "registerProcessObserver()");
+ synchronized (this) {
+ mProcessObservers.register(observer);
+ }
}
public void unregisterProcessObserver(IProcessObserver observer) {
- mProcessObservers.unregister(observer);
+ synchronized (this) {
+ mProcessObservers.unregister(observer);
+ }
}
public void setImmersive(IBinder token, boolean immersive) {
@@ -7456,6 +7507,7 @@
}
public boolean isTopActivityImmersive() {
+ enforceNotIsolatedCaller("startActivity");
synchronized (this) {
ActivityRecord r = mMainStack.topRunningActivityLocked(null);
return (r != null) ? r.immersive : false;
@@ -7867,7 +7919,7 @@
= (ApplicationInfo)apps.get(i);
if (info != null &&
!info.packageName.equals("android")) {
- addAppLocked(info);
+ addAppLocked(info, false);
}
}
}
@@ -7966,14 +8018,18 @@
private boolean handleAppCrashLocked(ProcessRecord app) {
long now = SystemClock.uptimeMillis();
- Long crashTime = mProcessCrashTimes.get(app.info.processName,
- app.info.uid);
+ Long crashTime;
+ if (!app.isolated) {
+ crashTime = mProcessCrashTimes.get(app.info.processName, app.uid);
+ } else {
+ crashTime = null;
+ }
if (crashTime != null && now < crashTime+ProcessList.MIN_CRASH_INTERVAL) {
// This process loses!
Slog.w(TAG, "Process " + app.info.processName
+ " has crashed too many times: killing!");
EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
- app.info.processName, app.info.uid);
+ app.info.processName, app.uid);
for (int i=mMainStack.mHistory.size()-1; i>=0; i--) {
ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
if (r.app == app) {
@@ -7987,11 +8043,15 @@
// explicitly does so... but for persistent process, we really
// need to keep it running. If a persistent process is actually
// repeatedly crashing, then badness for everyone.
- EventLog.writeEvent(EventLogTags.AM_PROC_BAD, app.info.uid,
+ EventLog.writeEvent(EventLogTags.AM_PROC_BAD, app.uid,
app.info.processName);
- mBadProcesses.put(app.info.processName, app.info.uid, now);
+ if (!app.isolated) {
+ // XXX We don't have a way to mark isolated processes
+ // as bad, since they don't have a peristent identity.
+ mBadProcesses.put(app.info.processName, app.uid, now);
+ mProcessCrashTimes.remove(app.info.processName, app.uid);
+ }
app.bad = true;
- mProcessCrashTimes.remove(app.info.processName, app.info.uid);
app.removed = true;
// Don't let services in this process be restarted and potentially
// annoy the user repeatedly. Unless it is persistent, since those
@@ -8063,7 +8123,12 @@
}
}
- mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
+ if (!app.isolated) {
+ // XXX Can't keep track of crash times for isolated processes,
+ // because they don't have a perisistent identity.
+ mProcessCrashTimes.put(app.info.processName, app.uid, now);
+ }
+
return true;
}
@@ -8561,8 +8626,10 @@
Intent appErrorIntent = null;
synchronized (this) {
- if (r != null) {
- mProcessCrashTimes.put(r.info.processName, r.info.uid,
+ if (r != null && !r.isolated) {
+ // XXX Can't keep track of crash time for isolated processes,
+ // since they don't have a persistent identity.
+ mProcessCrashTimes.put(r.info.processName, r.uid,
SystemClock.uptimeMillis());
}
if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
@@ -8625,6 +8692,7 @@
}
public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
+ enforceNotIsolatedCaller("getProcessesInErrorState");
// assume our apps are happy - lazy create the list
List<ActivityManager.ProcessErrorStateInfo> errList = null;
@@ -8687,6 +8755,7 @@
}
public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
+ enforceNotIsolatedCaller("getRunningAppProcesses");
// Lazy instantiation of list
List<ActivityManager.RunningAppProcessInfo> runList = null;
synchronized (this) {
@@ -8732,6 +8801,7 @@
}
public List<ApplicationInfo> getRunningExternalApplications() {
+ enforceNotIsolatedCaller("getRunningExternalApplications");
List<ActivityManager.RunningAppProcessInfo> runningApps = getRunningAppProcesses();
List<ApplicationInfo> retList = new ArrayList<ApplicationInfo>();
if (runningApps != null && runningApps.size() > 0) {
@@ -9025,8 +9095,13 @@
}
pw.println(" ");
- if (mMainStack.mPausingActivity != null) {
- pw.println(" mPausingActivity: " + mMainStack.mPausingActivity);
+ if (mMainStack.mPausingActivities.size() > 0) {
+ pw.println(" mPausingActivities: " + Arrays.toString(
+ mMainStack.mPausingActivities.toArray()));
+ }
+ if (mMainStack.mInputPausedActivities.size() > 0) {
+ pw.println(" mInputPausedActivities: " + Arrays.toString(
+ mMainStack.mInputPausedActivities.toArray()));
}
pw.println(" mResumedActivity: " + mMainStack.mResumedActivity);
pw.println(" mFocusedActivity: " + mFocusedActivity);
@@ -9095,7 +9170,21 @@
}
}
}
-
+
+ if (mIsolatedProcesses.size() > 0) {
+ if (needSep) pw.println(" ");
+ needSep = true;
+ pw.println(" Isolated process list (sorted by uid):");
+ for (int i=0; i<mIsolatedProcesses.size(); i++) {
+ ProcessRecord r = mIsolatedProcesses.valueAt(i);
+ if (dumpPackage != null && !dumpPackage.equals(r.info.packageName)) {
+ continue;
+ }
+ pw.println(String.format("%sIsolated #%2d: %s",
+ " ", i, r.toString()));
+ }
+ }
+
if (mLruProcesses.size() > 0) {
if (needSep) pw.println(" ");
needSep = true;
@@ -9500,98 +9589,7 @@
*/
protected boolean dumpProvider(FileDescriptor fd, PrintWriter pw, String name, String[] args,
int opti, boolean dumpAll) {
- ArrayList<ContentProviderRecord> providers = new ArrayList<ContentProviderRecord>();
-
- if ("all".equals(name)) {
- synchronized (this) {
- for (ContentProviderRecord r1 : mProvidersByClass.values()) {
- providers.add(r1);
- }
- }
- } else {
- ComponentName componentName = name != null
- ? ComponentName.unflattenFromString(name) : null;
- int objectId = 0;
- if (componentName == null) {
- // Not a '/' separated full component name; maybe an object ID?
- try {
- objectId = Integer.parseInt(name, 16);
- name = null;
- componentName = null;
- } catch (RuntimeException e) {
- }
- }
-
- synchronized (this) {
- for (ContentProviderRecord r1 : mProvidersByClass.values()) {
- if (componentName != null) {
- if (r1.name.equals(componentName)) {
- providers.add(r1);
- }
- } else if (name != null) {
- if (r1.name.flattenToString().contains(name)) {
- providers.add(r1);
- }
- } else if (System.identityHashCode(r1) == objectId) {
- providers.add(r1);
- }
- }
- }
- }
-
- if (providers.size() <= 0) {
- return false;
- }
-
- boolean needSep = false;
- for (int i=0; i<providers.size(); i++) {
- if (needSep) {
- pw.println();
- }
- needSep = true;
- dumpProvider("", fd, pw, providers.get(i), args, dumpAll);
- }
- return true;
- }
-
- /**
- * Invokes IApplicationThread.dumpProvider() on the thread of the specified provider if
- * there is a thread associated with the provider.
- */
- private void dumpProvider(String prefix, FileDescriptor fd, PrintWriter pw,
- final ContentProviderRecord r, String[] args, boolean dumpAll) {
- String innerPrefix = prefix + " ";
- synchronized (this) {
- pw.print(prefix); pw.print("PROVIDER ");
- pw.print(r);
- pw.print(" pid=");
- if (r.proc != null) pw.println(r.proc.pid);
- else pw.println("(not running)");
- if (dumpAll) {
- r.dump(pw, innerPrefix);
- }
- }
- if (r.proc != null && r.proc.thread != null) {
- pw.println(" Client:");
- pw.flush();
- try {
- TransferPipe tp = new TransferPipe();
- try {
- r.proc.thread.dumpProvider(
- tp.getWriteFd().getFileDescriptor(), r.provider.asBinder(), args);
- tp.setBufferPrefix(" ");
- // Short timeout, since blocking here can
- // deadlock with the application.
- tp.go(fd, 2000);
- } finally {
- tp.kill();
- }
- } catch (IOException ex) {
- pw.println(" Failure while dumping the provider: " + ex);
- } catch (RemoteException ex) {
- pw.println(" Got a RemoteException while dumping the service");
- }
- }
+ return mProviderMap.dumpProvider(fd, pw, name, args, opti, dumpAll);
}
static class ItemMatcher {
@@ -10880,6 +10878,7 @@
sr.stats.stopLaunchedLocked();
}
sr.app = null;
+ sr.isolatedProc = null;
sr.executeNesting = 0;
if (mStoppingServices.remove(sr)) {
if (DEBUG_SERVICE) Slog.v(TAG, "killServices remove stopping " + sr);
@@ -11115,10 +11114,11 @@
return;
}
- if (!app.persistent) {
+ if (!app.persistent || app.isolated) {
if (DEBUG_PROCESSES) Slog.v(TAG,
"Removing non-persistent process during cleanup: " + app);
- mProcessNames.remove(app.processName, app.info.uid);
+ mProcessNames.remove(app.processName, app.uid);
+ mIsolatedProcesses.remove(app.uid);
if (mHeavyWeightProcess == app) {
mHeavyWeightProcess = null;
mHandler.sendEmptyMessage(CANCEL_HEAVY_NOTIFICATION_MSG);
@@ -11143,10 +11143,10 @@
mPreviousProcess = null;
}
- if (restart) {
+ if (restart && !app.isolated) {
// We have components that still need to be running in the
// process, so re-launch it.
- mProcessNames.put(app.processName, app.info.uid, app);
+ mProcessNames.put(app.processName, app.uid, app);
startProcessLocked(app, "restart", app.processName);
} else if (app.pid > 0 && app.pid != MY_PID) {
// Goodbye!
@@ -11226,6 +11226,7 @@
public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
int flags) {
+ enforceNotIsolatedCaller("getServices");
synchronized (this) {
ArrayList<ActivityManager.RunningServiceInfo> res
= new ArrayList<ActivityManager.RunningServiceInfo>();
@@ -11252,6 +11253,7 @@
}
public PendingIntent getRunningServiceControlPanel(ComponentName name) {
+ enforceNotIsolatedCaller("getRunningServiceControlPanel");
synchronized (this) {
int userId = UserId.getUserId(Binder.getCallingUid());
ServiceRecord r = mServiceMap.getServiceByName(name, userId);
@@ -11353,18 +11355,18 @@
}
private ServiceLookupResult retrieveServiceLocked(Intent service,
- String resolvedType, int callingPid, int callingUid) {
+ String resolvedType, int callingPid, int callingUid, int userId) {
ServiceRecord r = null;
if (DEBUG_SERVICE)
Slog.v(TAG, "retrieveServiceLocked: " + service + " type=" + resolvedType
- + " origCallingUid=" + callingUid);
+ + " callingUid=" + callingUid);
if (service.getComponent() != null) {
- r = mServiceMap.getServiceByName(service.getComponent(), Binder.getOrigCallingUser());
+ r = mServiceMap.getServiceByName(service.getComponent(), userId);
}
if (r == null) {
Intent.FilterComparison filter = new Intent.FilterComparison(service);
- r = mServiceMap.getServiceByIntent(filter, Binder.getOrigCallingUser());
+ r = mServiceMap.getServiceByIntent(filter, userId);
}
if (r == null) {
try {
@@ -11378,13 +11380,12 @@
": not found");
return null;
}
- if (Binder.getOrigCallingUser() > 0) {
- sInfo.applicationInfo = getAppInfoForUser(sInfo.applicationInfo,
- Binder.getOrigCallingUser());
+ if (userId > 0) {
+ sInfo.applicationInfo = getAppInfoForUser(sInfo.applicationInfo, userId);
}
ComponentName name = new ComponentName(
sInfo.applicationInfo.packageName, sInfo.name);
- r = mServiceMap.getServiceByName(name, Binder.getOrigCallingUser());
+ r = mServiceMap.getServiceByName(name, userId);
if (r == null) {
Intent.FilterComparison filter = new Intent.FilterComparison(
service.cloneFilter());
@@ -11548,7 +11549,7 @@
}
if (DEBUG_MU)
Slog.v(TAG_MU, "realStartServiceLocked, ServiceRecord.uid = " + r.appInfo.uid
- + ", ProcessRecord.uid = " + app.info.uid);
+ + ", ProcessRecord.uid = " + app.uid);
r.app = app;
r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
@@ -11743,35 +11744,53 @@
+ r.packageName + ": " + e);
}
+ final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
final String appName = r.processName;
- ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
- if (DEBUG_MU)
- Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid + " app=" + app);
- if (app != null && app.thread != null) {
- try {
- app.addPackage(r.appInfo.packageName);
- realStartServiceLocked(r, app);
- return true;
- } catch (RemoteException e) {
- Slog.w(TAG, "Exception when starting service " + r.shortName, e);
- }
+ ProcessRecord app;
- // If a dead object exception was thrown -- fall through to
- // restart the application.
+ if (!isolated) {
+ app = getProcessRecordLocked(appName, r.appInfo.uid);
+ if (DEBUG_MU)
+ Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid + " app=" + app);
+ if (app != null && app.thread != null) {
+ try {
+ app.addPackage(r.appInfo.packageName);
+ realStartServiceLocked(r, app);
+ return true;
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Exception when starting service " + r.shortName, e);
+ }
+
+ // If a dead object exception was thrown -- fall through to
+ // restart the application.
+ }
+ } else {
+ // If this service runs in an isolated process, then each time
+ // we call startProcessLocked() we will get a new isolated
+ // process, starting another process if we are currently waiting
+ // for a previous process to come up. To deal with this, we store
+ // in the service any current isolated process it is running in or
+ // waiting to have come up.
+ app = r.isolatedProc;
}
// Not running -- get it started, and enqueue this service record
// to be executed when the app comes up.
- if (startProcessLocked(appName, r.appInfo, true, intentFlags,
- "service", r.name, false) == null) {
- Slog.w(TAG, "Unable to launch app "
- + r.appInfo.packageName + "/"
- + r.appInfo.uid + " for service "
- + r.intent.getIntent() + ": process is bad");
- bringDownServiceLocked(r, true);
- return false;
+ if (app == null) {
+ if ((app=startProcessLocked(appName, r.appInfo, true, intentFlags,
+ "service", r.name, false, isolated)) == null) {
+ Slog.w(TAG, "Unable to launch app "
+ + r.appInfo.packageName + "/"
+ + r.appInfo.uid + " for service "
+ + r.intent.getIntent() + ": process is bad");
+ bringDownServiceLocked(r, true);
+ return false;
+ }
+ if (isolated) {
+ r.isolatedProc = app;
+ }
}
-
+
if (!mPendingServices.contains(r)) {
mPendingServices.add(r);
}
@@ -11930,7 +11949,7 @@
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType,
- callingPid, callingUid);
+ callingPid, callingUid, UserId.getUserId(callingUid));
if (res == null) {
return null;
}
@@ -11961,6 +11980,7 @@
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType) {
+ enforceNotIsolatedCaller("startService");
// Refuse possible leaked file descriptors
if (service != null && service.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
@@ -12003,6 +12023,7 @@
public int stopService(IApplicationThread caller, Intent service,
String resolvedType) {
+ enforceNotIsolatedCaller("stopService");
// Refuse possible leaked file descriptors
if (service != null && service.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
@@ -12040,6 +12061,7 @@
}
public IBinder peekService(Intent service, String resolvedType) {
+ enforceNotIsolatedCaller("peekService");
// Refuse possible leaked file descriptors
if (service != null && service.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
@@ -12177,12 +12199,15 @@
public int bindService(IApplicationThread caller, IBinder token,
Intent service, String resolvedType,
- IServiceConnection connection, int flags) {
+ IServiceConnection connection, int flags, int userId) {
+ enforceNotIsolatedCaller("bindService");
// Refuse possible leaked file descriptors
if (service != null && service.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
+ checkValidCaller(Binder.getCallingUid(), userId);
+
synchronized(this) {
if (DEBUG_SERVICE) Slog.v(TAG, "bindService: " + service
+ " type=" + resolvedType + " conn=" + connection.asBinder()
@@ -12232,7 +12257,7 @@
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType,
- Binder.getCallingPid(), Binder.getOrigCallingUid());
+ Binder.getCallingPid(), Binder.getCallingUid(), userId);
if (res == null) {
return 0;
}
@@ -12687,7 +12712,7 @@
: new ComponentName("android", "FullBackupAgent");
// startProcessLocked() returns existing proc's record if it's already running
ProcessRecord proc = startProcessLocked(app.processName, app,
- false, 0, "backup", hostingName, false);
+ false, 0, "backup", hostingName, false, false);
if (proc == null) {
Slog.e(TAG, "Unable to start backup agent process " + r);
return false;
@@ -12834,6 +12859,7 @@
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter, String permission) {
+ enforceNotIsolatedCaller("registerReceiver");
synchronized(this) {
ProcessRecord callerApp = null;
if (caller != null) {
@@ -13343,6 +13369,7 @@
Intent intent, String resolvedType, IIntentReceiver resultTo,
int resultCode, String resultData, Bundle map,
String requiredPermission, boolean serialized, boolean sticky, int userId) {
+ enforceNotIsolatedCaller("broadcastIntent");
synchronized(this) {
intent = verifyBroadcastLocked(intent);
@@ -13589,6 +13616,7 @@
public boolean startInstrumentation(ComponentName className,
String profileFile, int flags, Bundle arguments,
IInstrumentationWatcher watcher) {
+ enforceNotIsolatedCaller("startInstrumentation");
// Refuse possible leaked file descriptors
if (arguments != null && arguments.hasFileDescriptors()) {
throw new IllegalArgumentException("File descriptors passed in Bundle");
@@ -13632,7 +13660,7 @@
final long origId = Binder.clearCallingIdentity();
// Instrumentation can kill and relaunch even persistent processes
forceStopPackageLocked(ii.targetPackage, -1, true, false, true, true);
- ProcessRecord app = addAppLocked(ai);
+ ProcessRecord app = addAppLocked(ai, false);
app.instrumentationClass = className;
app.instrumentationInfo = ai;
app.instrumentationProfileFile = profileFile;
@@ -13786,8 +13814,11 @@
* configuration.
* @param persistent TODO
*/
- public boolean updateConfigurationLocked(Configuration values,
+ boolean updateConfigurationLocked(Configuration values,
ActivityRecord starting, boolean persistent, boolean initLocale) {
+ // do nothing if we are headless
+ if (mHeadless) return true;
+
int changes = 0;
boolean kept = true;
@@ -13817,6 +13848,10 @@
Slog.i(TAG, "Config changed: " + newConfig);
final Configuration configCopy = new Configuration(mConfiguration);
+
+ // TODO: If our config changes, should we auto dismiss any currently
+ // showing dialogs?
+ mShowDialogs = shouldShowDialogs(newConfig);
AttributeCache ac = AttributeCache.instance();
if (ac != null) {
@@ -13883,6 +13918,19 @@
return kept;
}
+
+ /**
+ * Decide based on the configuration whether we should shouw the ANR,
+ * crash, etc dialogs. The idea is that if there is no affordnace to
+ * press the on-screen buttons, we shouldn't show the dialog.
+ *
+ * A thought: SystemUI might also want to get told about this, the Power
+ * dialog / global actions also might want different behaviors.
+ */
+ private static final boolean shouldShowDialogs(Configuration config) {
+ return !(config.keyboard == Configuration.KEYBOARD_NOKEYS
+ && config.touchscreen == Configuration.TOUCHSCREEN_NOTOUCH);
+ }
/**
* Save the locale. You must be inside a synchronized (this) block.
@@ -14759,7 +14807,13 @@
private final ActivityRecord resumedAppLocked() {
ActivityRecord resumedActivity = mMainStack.mResumedActivity;
if (resumedActivity == null || resumedActivity.app == null) {
- resumedActivity = mMainStack.mPausingActivity;
+ for (int i=mMainStack.mPausingActivities.size()-1; i>=0; i--) {
+ ActivityRecord r = mMainStack.mPausingActivities.get(i);
+ if (r.app != null) {
+ resumedActivity = r;
+ break;
+ }
+ }
if (resumedActivity == null || resumedActivity.app == null) {
resumedActivity = mMainStack.topRunningActivityLocked(null);
}
@@ -14839,6 +14893,20 @@
Process.killProcessQuiet(app.pid);
}
}
+ if (!app.killedBackground && app.isolated && app.services.size() <= 0) {
+ // If this is an isolated process, and there are no
+ // services running in it, then the process is no longer
+ // needed. We agressively kill these because we can by
+ // definition not re-use the same process again, and it is
+ // good to avoid having whatever code was running in them
+ // left sitting around after no longer needed.
+ Slog.i(TAG, "Isolated process " + app.processName
+ + " (pid " + app.pid + ") no longer needed");
+ EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
+ app.processName, app.setAdj, "isolated not needed");
+ app.killedBackground = true;
+ Process.killProcessQuiet(app.pid);
+ }
}
}
@@ -14977,7 +15045,7 @@
if (app.persistent) {
if (app.persistent) {
- addAppLocked(app.info);
+ addAppLocked(app.info, false);
}
}
}
@@ -15186,7 +15254,7 @@
synchronized (this) { }
}
- public void onCoreSettingsChange(Bundle settings) {
+ void onCoreSettingsChange(Bundle settings) {
for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
ProcessRecord processRecord = mLruProcesses.get(i);
try {
@@ -15203,6 +15271,25 @@
private int mCurrentUserId;
private SparseIntArray mLoggedInUsers = new SparseIntArray(5);
+ private ArrayList<UserListener> mUserListeners = new ArrayList<UserListener>(3);
+
+ public interface UserListener {
+ public void onUserChanged(int userId);
+
+ public void onUserAdded(int userId);
+
+ public void onUserRemoved(int userId);
+
+ public void onUserLoggedOut(int userId);
+ }
+
+ public void addUserListener(UserListener listener) {
+ synchronized (this) {
+ if (!mUserListeners.contains(listener)) {
+ mUserListeners.add(listener);
+ }
+ }
+ }
public boolean switchUser(int userId) {
final int callingUid = Binder.getCallingUid();
@@ -15213,6 +15300,8 @@
if (mCurrentUserId == userId)
return true;
+ ArrayList<UserListener> listeners;
+
synchronized (this) {
// Check if user is already logged in, otherwise check if user exists first before
// adding to the list of logged in users.
@@ -15228,6 +15317,12 @@
if (!haveActivities) {
startHomeActivityLocked(userId);
}
+
+ listeners = (ArrayList<UserListener>) mUserListeners.clone();
+ }
+ // Inform the listeners
+ for (UserListener listener : listeners) {
+ listener.onUserChanged(userId);
}
return true;
}
@@ -15247,6 +15342,12 @@
return false;
}
+ private void checkValidCaller(int uid, int userId) {
+ if (UserId.getUserId(uid) == userId || uid == Process.SYSTEM_UID || uid == 0) return;
+
+ throw new SecurityException("Caller uid=" + uid
+ + " is not privileged to communicate with user=" + userId);
+ }
private int applyUserId(int uid, int userId) {
return UserId.getUid(userId, uid);
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index cdab6c6..977ee84 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -602,6 +602,7 @@
public void windowsDrawn() {
synchronized(service) {
+ stack.reportActivityDrawnLocked(this);
if (launchTime != 0) {
final long curTime = SystemClock.uptimeMillis();
final long thisTime = curTime - launchTime;
@@ -690,7 +691,9 @@
// Hmmm, who might we be waiting for?
r = stack.mResumedActivity;
if (r == null) {
- r = stack.mPausingActivity;
+ if (stack.mPausingActivities.size() > 0) {
+ r = stack.mPausingActivities.get(stack.mPausingActivities.size()-1);
+ }
}
// Both of those null? Fall back to 'this' again
if (r == null) {
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index c3ae6a1..f59f0c1 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -227,7 +227,13 @@
* When we are in the process of pausing an activity, before starting the
* next one, this variable holds the activity that is currently being paused.
*/
- ActivityRecord mPausingActivity = null;
+ final ArrayList<ActivityRecord> mPausingActivities = new ArrayList<ActivityRecord>();
+
+ /**
+ * These activities currently have their input paused, as they want for
+ * the next top activity to have its windows visible.
+ */
+ final ArrayList<ActivityRecord> mInputPausedActivities = new ArrayList<ActivityRecord>();
/**
* This is the last activity that we put into the paused state. This is
@@ -755,7 +761,7 @@
}
mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
- "activity", r.intent.getComponent(), false);
+ "activity", r.intent.getComponent(), false, false);
}
void stopIfSleepingLocked() {
@@ -807,9 +813,9 @@
startPausingLocked(false, true);
return;
}
- if (mPausingActivity != null) {
+ if (mPausingActivities.size() > 0) {
// Still waiting for something to pause; can't sleep yet.
- if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still waiting to pause " + mPausingActivity);
+ if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still waiting to pause " + mPausingActivities);
return;
}
@@ -872,11 +878,6 @@
}
private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
- if (mPausingActivity != null) {
- RuntimeException e = new RuntimeException();
- Slog.e(TAG, "Trying to pause when pause is already pending for "
- + mPausingActivity, e);
- }
ActivityRecord prev = mResumedActivity;
if (prev == null) {
RuntimeException e = new RuntimeException();
@@ -884,19 +885,25 @@
resumeTopActivityLocked(null);
return;
}
+ if (mPausingActivities.contains(prev)) {
+ RuntimeException e = new RuntimeException();
+ Slog.e(TAG, "Trying to pause when pause when already pausing " + prev, e);
+ }
if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSING: " + prev);
else if (DEBUG_PAUSE) Slog.v(TAG, "Start pausing: " + prev);
mResumedActivity = null;
- mPausingActivity = prev;
+ mPausingActivities.add(prev);
mLastPausedActivity = prev;
prev.state = ActivityState.PAUSING;
prev.task.touchActiveTime();
prev.updateThumbnail(screenshotActivities(prev), null);
mService.updateCpuStats();
+ ActivityRecord pausing;
if (prev.app != null && prev.app.thread != null) {
if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending pause: " + prev);
+ pausing = prev;
try {
EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
System.identityHashCode(prev),
@@ -909,12 +916,14 @@
} catch (Exception e) {
// Ignore exception, if process died other code will cleanup.
Slog.w(TAG, "Exception thrown during pause", e);
- mPausingActivity = null;
+ mPausingActivities.remove(prev);
mLastPausedActivity = null;
+ pausing = null;
}
} else {
- mPausingActivity = null;
+ mPausingActivities.remove(prev);
mLastPausedActivity = null;
+ pausing = null;
}
// If we are not going to sleep, we want to ensure the device is
@@ -928,18 +937,28 @@
}
}
-
- if (mPausingActivity != null) {
+ if (pausing != null) {
// Have the window manager pause its key dispatching until the new
// activity has started. If we're pausing the activity just because
// the screen is being turned off and the UI is sleeping, don't interrupt
// key dispatch; the same activity will pick it up again on wakeup.
if (!uiSleeping) {
- prev.pauseKeyDispatchingLocked();
+ pausing.pauseKeyDispatchingLocked();
+ mInputPausedActivities.add(prev);
} else {
if (DEBUG_PAUSE) Slog.v(TAG, "Key dispatch not paused for screen off");
}
+ if (pausing.configDestroy) {
+ // The previous is being paused because the configuration
+ // is changing, which means it is actually stopping...
+ // To juggle the fact that we are also starting a new
+ // instance right now, we need to first completely stop
+ // the current instance before starting the new one.
+ if (DEBUG_PAUSE) Slog.v(TAG, "Destroying at pause: " + prev);
+ destroyActivityLocked(pausing, true, false, "pause-config");
+ }
+
// Schedule a pause timeout in case the app doesn't respond.
// We don't give it much time because this directly impacts the
// responsiveness seen by the user.
@@ -951,7 +970,10 @@
// This activity failed to schedule the
// pause, so just treat it as being paused now.
if (DEBUG_PAUSE) Slog.v(TAG, "Activity not running, resuming next.");
- resumeTopActivityLocked(null);
+ }
+
+ if (!mService.isSleeping()) {
+ resumeTopActivityLocked(pausing);
}
}
@@ -966,16 +988,17 @@
if (index >= 0) {
r = mHistory.get(index);
mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
- if (mPausingActivity == r) {
+ if (mPausingActivities.contains(r)) {
if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSED: " + r
+ (timeout ? " (due to timeout)" : " (pause complete)"));
r.state = ActivityState.PAUSED;
- completePauseLocked();
+ completePauseLocked(r);
} else {
+ ActivityRecord old = mPausingActivities.size() > 0
+ ? mPausingActivities.get(0) : null;
EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
System.identityHashCode(r), r.shortComponentName,
- mPausingActivity != null
- ? mPausingActivity.shortComponentName : "(none)");
+ old != null ? old.shortComponentName : "(none)");
}
}
}
@@ -1001,8 +1024,14 @@
ProcessRecord fgApp = null;
if (mResumedActivity != null) {
fgApp = mResumedActivity.app;
- } else if (mPausingActivity != null) {
- fgApp = mPausingActivity.app;
+ } else {
+ for (int i=mPausingActivities.size()-1; i>=0; i--) {
+ ActivityRecord pausing = mPausingActivities.get(i);
+ if (pausing.app == r.app) {
+ fgApp = pausing.app;
+ break;
+ }
+ }
}
if (r.app != null && fgApp != null && r.app != fgApp
&& r.lastVisibleTime > mService.mPreviousProcessVisibleTime
@@ -1014,57 +1043,48 @@
}
}
- private final void completePauseLocked() {
- ActivityRecord prev = mPausingActivity;
+ private final void completePauseLocked(ActivityRecord prev) {
if (DEBUG_PAUSE) Slog.v(TAG, "Complete pause: " + prev);
- if (prev != null) {
- if (prev.finishing) {
- if (DEBUG_PAUSE) Slog.v(TAG, "Executing finish of activity: " + prev);
- prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
- } else if (prev.app != null) {
- if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending stop: " + prev);
- if (prev.waitingVisible) {
- prev.waitingVisible = false;
- mWaitingVisibleActivities.remove(prev);
- if (DEBUG_SWITCH || DEBUG_PAUSE) Slog.v(
- TAG, "Complete pause, no longer waiting: " + prev);
- }
- if (prev.configDestroy) {
- // The previous is being paused because the configuration
- // is changing, which means it is actually stopping...
- // To juggle the fact that we are also starting a new
- // instance right now, we need to first completely stop
- // the current instance before starting the new one.
- if (DEBUG_PAUSE) Slog.v(TAG, "Destroying after pause: " + prev);
- destroyActivityLocked(prev, true, false, "pause-config");
- } else {
- mStoppingActivities.add(prev);
- if (mStoppingActivities.size() > 3) {
- // If we already have a few activities waiting to stop,
- // then give up on things going idle and start clearing
- // them out.
- if (DEBUG_PAUSE) Slog.v(TAG, "To many pending stops, forcing idle");
- scheduleIdleLocked();
- } else {
- checkReadyForSleepLocked();
- }
- }
- } else {
- if (DEBUG_PAUSE) Slog.v(TAG, "App died during pause, not stopping: " + prev);
- prev = null;
+ if (prev.finishing) {
+ if (DEBUG_PAUSE) Slog.v(TAG, "Executing finish of activity: " + prev);
+ prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
+ } else if (prev.app != null) {
+ if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending stop: " + prev);
+ if (prev.waitingVisible) {
+ prev.waitingVisible = false;
+ mWaitingVisibleActivities.remove(prev);
+ if (DEBUG_SWITCH || DEBUG_PAUSE) Slog.v(
+ TAG, "Complete pause, no longer waiting: " + prev);
}
- mPausingActivity = null;
- }
-
- if (!mService.isSleeping()) {
- resumeTopActivityLocked(prev);
+ if (prev.configDestroy) {
+ // The previous is being paused because the configuration
+ // is changing, which means it is actually stopping...
+ // To juggle the fact that we are also starting a new
+ // instance right now, we need to first completely stop
+ // the current instance before starting the new one.
+ if (DEBUG_PAUSE) Slog.v(TAG, "Destroying after pause: " + prev);
+ destroyActivityLocked(prev, true, false, "pause-config");
+ } else {
+ mStoppingActivities.add(prev);
+ if (mStoppingActivities.size() > 3) {
+ // If we already have a few activities waiting to stop,
+ // then give up on things going idle and start clearing
+ // them out.
+ if (DEBUG_PAUSE) Slog.v(TAG, "To many pending stops, forcing idle");
+ scheduleIdleLocked();
+ } else {
+ checkReadyForSleepLocked();
+ }
+ }
} else {
- checkReadyForSleepLocked();
+ if (DEBUG_PAUSE) Slog.v(TAG, "App died during pause, not stopping: " + prev);
+ prev = null;
}
-
- if (prev != null) {
- prev.resumeKeyDispatchingLocked();
+ mPausingActivities.remove(prev);
+
+ if (mService.isSleeping()) {
+ checkReadyForSleepLocked();
}
if (prev.app != null && prev.cpuTimeAtResume > 0
@@ -1122,7 +1142,9 @@
if (mMainStack) {
mService.setFocusedActivityLocked(next);
}
- next.resumeKeyDispatchingLocked();
+ if (mInputPausedActivities.remove(next)) {
+ next.resumeKeyDispatchingLocked();
+ }
ensureActivitiesVisibleLocked(null, 0);
mService.mWindowManager.executeAppTransition();
mNoAnimActivities.clear();
@@ -1352,13 +1374,6 @@
if (DEBUG_SWITCH) Slog.v(TAG, "Resuming " + next);
- // If we are currently pausing an activity, then don't do anything
- // until that is done.
- if (mPausingActivity != null) {
- if (DEBUG_SWITCH) Slog.v(TAG, "Skip resume: pausing=" + mPausingActivity);
- return false;
- }
-
// Okay we are now going to start a switch, to 'next'. We may first
// have to pause the current activity, but this is an important point
// where we have decided to go to 'next' so keep track of that.
@@ -2440,7 +2455,7 @@
err = startActivityUncheckedLocked(r, sourceRecord,
grantedUriPermissions, grantedMode, onlyIfNeeded, true);
- if (mDismissKeyguardOnNextActivity && mPausingActivity == null) {
+ if (mDismissKeyguardOnNextActivity && mPausingActivities.size() == 0) {
// Someone asked to have the keyguard dismissed on the next
// activity start, but we are not actually doing an activity
// switch... just dismiss the keyguard now, because we
@@ -3111,7 +3126,18 @@
}
mService.notifyAll();
}
-
+
+ void reportActivityDrawnLocked(ActivityRecord r) {
+ if (mResumedActivity == r) {
+ // Once the resumed activity has been drawn, we can stop
+ // pausing input on all other activities.
+ for (int i=mInputPausedActivities.size()-1; i>=0; i--) {
+ mInputPausedActivities.get(i).resumeKeyDispatchingLocked();
+ }
+ mInputPausedActivities.clear();
+ }
+ }
+
void reportActivityVisibleLocked(ActivityRecord r) {
for (int i=mWaitingActivityVisible.size()-1; i>=0; i--) {
WaitResult w = mWaitingActivityVisible.get(i);
@@ -3170,7 +3196,9 @@
mService.setFocusedActivityLocked(topRunningActivityLocked(null));
}
}
- r.resumeKeyDispatchingLocked();
+ if (mInputPausedActivities.remove(r)) {
+ r.resumeKeyDispatchingLocked();
+ }
try {
r.stopped = false;
if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPING: " + r
@@ -3496,7 +3524,7 @@
// Tell window manager to prepare for this one to be removed.
mService.mWindowManager.setAppVisibility(r.appToken, false);
- if (mPausingActivity == null) {
+ if (!mPausingActivities.contains(r)) {
if (DEBUG_PAUSE) Slog.v(TAG, "Finish needs to pause: " + r);
if (DEBUG_USER_LEAVING) Slog.v(TAG, "finish() => pause with userLeaving=false");
startPausingLocked(false, false);
@@ -3580,6 +3608,20 @@
return r;
}
+ final void appDiedLocked(ProcessRecord app) {
+ for (int i=mPausingActivities.size()-1; i>=0; i--) {
+ ActivityRecord r = mPausingActivities.get(i);
+ if (r.app == app) {
+ if (DEBUG_PAUSE) Slog.v(TAG, "App died while pausing: " + r);
+ mPausingActivities.remove(i);
+ mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
+ }
+ }
+ if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
+ mLastPausedActivity = null;
+ }
+ }
+
/**
* Perform the common clean-up of an activity record. This is called both
* as part of destroyActivityLocked() (when destroying the client-side
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 72292be..b64261d 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -28,7 +28,9 @@
import android.content.res.CompatibilityInfo;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.Process;
import android.os.SystemClock;
+import android.os.UserId;
import android.util.PrintWriterPrinter;
import android.util.TimeUtils;
@@ -44,6 +46,9 @@
class ProcessRecord {
final BatteryStatsImpl.Uid.Proc batteryStats; // where to collect runtime statistics
final ApplicationInfo info; // all about the first app in the process
+ final boolean isolated; // true if this is a special isolated process
+ final int uid; // uid of process; may be different from 'info' if isolated
+ final int userId; // user of process.
final String processName; // name of the process
// List of packages running in the process
final HashSet<String> pkgList = new HashSet<String>();
@@ -147,6 +152,12 @@
void dump(PrintWriter pw, String prefix) {
final long now = SystemClock.uptimeMillis();
+ pw.print(prefix); pw.print("user #"); pw.print(userId);
+ pw.print(" uid="); pw.print(info.uid);
+ if (uid != info.uid) {
+ pw.print(" ISOLATED uid="); pw.print(uid);
+ }
+ pw.println();
if (info.className != null) {
pw.print(prefix); pw.print("class="); pw.println(info.className);
}
@@ -267,9 +278,12 @@
}
ProcessRecord(BatteryStatsImpl.Uid.Proc _batteryStats, IApplicationThread _thread,
- ApplicationInfo _info, String _processName) {
+ ApplicationInfo _info, String _processName, int _uid) {
batteryStats = _batteryStats;
info = _info;
+ isolated = _info.uid != _uid;
+ uid = _uid;
+ userId = UserId.getUserId(_uid);
processName = _processName;
pkgList.add(_info.packageName);
thread = _thread;
@@ -343,7 +357,18 @@
sb.append(':');
sb.append(processName);
sb.append('/');
- sb.append(info.uid);
+ if (info.uid < Process.FIRST_APPLICATION_UID) {
+ sb.append(uid);
+ } else {
+ sb.append('u');
+ sb.append(userId);
+ sb.append('a');
+ sb.append(info.uid%Process.FIRST_APPLICATION_UID);
+ if (uid != info.uid) {
+ sb.append('i');
+ sb.append(UserId.getAppId(uid) - Process.FIRST_ISOLATED_UID);
+ }
+ }
}
public String toString() {
diff --git a/services/java/com/android/server/am/ProviderMap.java b/services/java/com/android/server/am/ProviderMap.java
index 44e7ecc..2021e0d 100644
--- a/services/java/com/android/server/am/ProviderMap.java
+++ b/services/java/com/android/server/am/ProviderMap.java
@@ -17,17 +17,22 @@
package com.android.server.am;
import android.content.ComponentName;
-import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.Process;
+import android.os.RemoteException;
import android.os.UserId;
import android.util.Slog;
import android.util.SparseArray;
+import java.io.FileDescriptor;
+import java.io.IOException;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
/**
* Keeps track of content providers by authority (name) and class. It separates the mapping by
@@ -153,7 +158,7 @@
}
}
- private HashMap<ComponentName, ContentProviderRecord> getProvidersByClass(int optionalUserId) {
+ HashMap<ComponentName, ContentProviderRecord> getProvidersByClass(int optionalUserId) {
final int userId = optionalUserId >= 0
? optionalUserId : Binder.getOrigCallingUser();
final HashMap<ComponentName, ContentProviderRecord> map = mProvidersByClassPerUser.get(userId);
@@ -241,4 +246,102 @@
}
}
}
+
+ protected boolean dumpProvider(FileDescriptor fd, PrintWriter pw, String name, String[] args,
+ int opti, boolean dumpAll) {
+ ArrayList<ContentProviderRecord> providers = new ArrayList<ContentProviderRecord>();
+
+ if ("all".equals(name)) {
+ synchronized (this) {
+ for (ContentProviderRecord r1 : getProvidersByClass(-1).values()) {
+ providers.add(r1);
+ }
+ }
+ } else {
+ ComponentName componentName = name != null
+ ? ComponentName.unflattenFromString(name) : null;
+ int objectId = 0;
+ if (componentName == null) {
+ // Not a '/' separated full component name; maybe an object ID?
+ try {
+ objectId = Integer.parseInt(name, 16);
+ name = null;
+ componentName = null;
+ } catch (RuntimeException e) {
+ }
+ }
+
+ synchronized (this) {
+ for (ContentProviderRecord r1 : getProvidersByClass(-1).values()) {
+ if (componentName != null) {
+ if (r1.name.equals(componentName)) {
+ providers.add(r1);
+ }
+ } else if (name != null) {
+ if (r1.name.flattenToString().contains(name)) {
+ providers.add(r1);
+ }
+ } else if (System.identityHashCode(r1) == objectId) {
+ providers.add(r1);
+ }
+ }
+ }
+ }
+
+ if (providers.size() <= 0) {
+ return false;
+ }
+
+ boolean needSep = false;
+ for (int i=0; i<providers.size(); i++) {
+ if (needSep) {
+ pw.println();
+ }
+ needSep = true;
+ dumpProvider("", fd, pw, providers.get(i), args, dumpAll);
+ }
+ return true;
+ }
+
+ /**
+ * Invokes IApplicationThread.dumpProvider() on the thread of the specified provider if
+ * there is a thread associated with the provider.
+ */
+ private void dumpProvider(String prefix, FileDescriptor fd, PrintWriter pw,
+ final ContentProviderRecord r, String[] args, boolean dumpAll) {
+ String innerPrefix = prefix + " ";
+ synchronized (this) {
+ pw.print(prefix); pw.print("PROVIDER ");
+ pw.print(r);
+ pw.print(" pid=");
+ if (r.proc != null) pw.println(r.proc.pid);
+ else pw.println("(not running)");
+ if (dumpAll) {
+ r.dump(pw, innerPrefix);
+ }
+ }
+ if (r.proc != null && r.proc.thread != null) {
+ pw.println(" Client:");
+ pw.flush();
+ try {
+ TransferPipe tp = new TransferPipe();
+ try {
+ r.proc.thread.dumpProvider(
+ tp.getWriteFd().getFileDescriptor(), r.provider.asBinder(), args);
+ tp.setBufferPrefix(" ");
+ // Short timeout, since blocking here can
+ // deadlock with the application.
+ tp.go(fd, 2000);
+ } finally {
+ tp.kill();
+ }
+ } catch (IOException ex) {
+ pw.println(" Failure while dumping the provider: " + ex);
+ } catch (RemoteException ex) {
+ pw.println(" Got a RemoteException while dumping the service");
+ }
+ }
+ }
+
+
}
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java
index 75ba9474..daa3653 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/java/com/android/server/am/ServiceRecord.java
@@ -80,6 +80,7 @@
// IBinder -> ConnectionRecord of all bound clients
ProcessRecord app; // where this service is running or null.
+ ProcessRecord isolatedProc; // keep track of isolated process, if requested
boolean isForeground; // is service currently in foreground mode?
int foregroundId; // Notification ID of last foreground req.
Notification foregroundNoti; // Notification record of foreground state.
@@ -210,6 +211,9 @@
}
pw.print(prefix); pw.print("dataDir="); pw.println(dataDir);
pw.print(prefix); pw.print("app="); pw.println(app);
+ if (isolatedProc != null) {
+ pw.print(prefix); pw.print("isolatedProc="); pw.println(isolatedProc);
+ }
if (isForeground || foregroundId != 0) {
pw.print(prefix); pw.print("isForeground="); pw.print(isForeground);
pw.print(" foregroundId="); pw.print(foregroundId);
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 38c128c..7169015 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -164,13 +164,9 @@
private static final boolean DEBUG_APP_DIR_OBSERVER = false;
private static final boolean DEBUG_VERIFY = false;
- static final boolean MULTIPLE_APPLICATION_UIDS = true;
private static final int RADIO_UID = Process.PHONE_UID;
private static final int LOG_UID = Process.LOG_UID;
private static final int NFC_UID = Process.NFC_UID;
- static final int FIRST_APPLICATION_UID =
- Process.FIRST_APPLICATION_UID;
- static final int MAX_APPLICATION_UIDS = 1000;
private static final boolean GET_CERTIFICATES = true;
@@ -874,18 +870,9 @@
mSettings = new Settings();
mSettings.addSharedUserLPw("android.uid.system",
Process.SYSTEM_UID, ApplicationInfo.FLAG_SYSTEM);
- mSettings.addSharedUserLPw("android.uid.phone",
- MULTIPLE_APPLICATION_UIDS
- ? RADIO_UID : FIRST_APPLICATION_UID,
- ApplicationInfo.FLAG_SYSTEM);
- mSettings.addSharedUserLPw("android.uid.log",
- MULTIPLE_APPLICATION_UIDS
- ? LOG_UID : FIRST_APPLICATION_UID,
- ApplicationInfo.FLAG_SYSTEM);
- mSettings.addSharedUserLPw("android.uid.nfc",
- MULTIPLE_APPLICATION_UIDS
- ? NFC_UID : FIRST_APPLICATION_UID,
- ApplicationInfo.FLAG_SYSTEM);
+ mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID, ApplicationInfo.FLAG_SYSTEM);
+ mSettings.addSharedUserLPw("android.uid.log", LOG_UID, ApplicationInfo.FLAG_SYSTEM);
+ mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID, ApplicationInfo.FLAG_SYSTEM);
String separateProcesses = SystemProperties.get("debug.separate_processes");
if (separateProcesses != null && separateProcesses.length() > 0) {
@@ -2274,8 +2261,6 @@
}
}
- final int userId = UserId.getUserId(Binder.getCallingUid());
-
if (comp != null) {
final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
final ActivityInfo ai = getActivityInfo(comp, flags);
@@ -6446,10 +6431,6 @@
// package that we deleted.
if(deletedPkg) {
File restoreFile = new File(deletedPackage.mPath);
- if (restoreFile == null) {
- Slog.e(TAG, "Failed allocating storage when restoring pkg : " + pkgName);
- return;
- }
// Parse old package
boolean oldOnSd = isExternal(deletedPackage);
int oldParseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY |
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index 3616aa2..ebf954bf 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -200,11 +200,7 @@
return null;
}
s = new SharedUserSetting(name, pkgFlags);
- if (PackageManagerService.MULTIPLE_APPLICATION_UIDS) {
- s.userId = newUserIdLPw(s);
- } else {
- s.userId = PackageManagerService.FIRST_APPLICATION_UID;
- }
+ s.userId = newUserIdLPw(s);
Log.i(PackageManagerService.TAG, "New shared user " + name + ": id=" + s.userId);
// < 0 means we couldn't assign a userid; fall out and return
// s, which is currently null
@@ -407,7 +403,7 @@
}
if (sharedUser != null) {
p.userId = sharedUser.userId;
- } else if (PackageManagerService.MULTIPLE_APPLICATION_UIDS) {
+ } else {
// Clone the setting here for disabled system packages
PackageSetting dis = mDisabledSysPackages.get(name);
if (dis != null) {
@@ -430,8 +426,6 @@
// Assign new user id
p.userId = newUserIdLPw(p);
}
- } else {
- p.userId = PackageManagerService.FIRST_APPLICATION_UID;
}
}
if (p.userId < 0) {
@@ -598,13 +592,13 @@
}
private boolean addUserIdLPw(int uid, Object obj, Object name) {
- if (uid >= PackageManagerService.FIRST_APPLICATION_UID + PackageManagerService.MAX_APPLICATION_UIDS) {
+ if (uid > Process.LAST_APPLICATION_UID) {
return false;
}
- if (uid >= PackageManagerService.FIRST_APPLICATION_UID) {
+ if (uid >= Process.FIRST_APPLICATION_UID) {
int N = mUserIds.size();
- final int index = uid - PackageManagerService.FIRST_APPLICATION_UID;
+ final int index = uid - Process.FIRST_APPLICATION_UID;
while (index >= N) {
mUserIds.add(null);
N++;
@@ -629,9 +623,9 @@
}
public Object getUserIdLPr(int uid) {
- if (uid >= PackageManagerService.FIRST_APPLICATION_UID) {
+ if (uid >= Process.FIRST_APPLICATION_UID) {
final int N = mUserIds.size();
- final int index = uid - PackageManagerService.FIRST_APPLICATION_UID;
+ final int index = uid - Process.FIRST_APPLICATION_UID;
return index < N ? mUserIds.get(index) : null;
} else {
return mOtherUserIds.get(uid);
@@ -639,9 +633,9 @@
}
private void removeUserIdLPw(int uid) {
- if (uid >= PackageManagerService.FIRST_APPLICATION_UID) {
+ if (uid >= Process.FIRST_APPLICATION_UID) {
final int N = mUserIds.size();
- final int index = uid - PackageManagerService.FIRST_APPLICATION_UID;
+ final int index = uid - Process.FIRST_APPLICATION_UID;
if (index < N) mUserIds.set(index, null);
} else {
mOtherUserIds.remove(uid);
@@ -649,9 +643,9 @@
}
private void replaceUserIdLPw(int uid, Object obj) {
- if (uid >= PackageManagerService.FIRST_APPLICATION_UID) {
+ if (uid >= Process.FIRST_APPLICATION_UID) {
final int N = mUserIds.size();
- final int index = uid - PackageManagerService.FIRST_APPLICATION_UID;
+ final int index = uid - Process.FIRST_APPLICATION_UID;
if (index < N) mUserIds.set(index, obj);
} else {
mOtherUserIds.put(uid, obj);
@@ -1898,17 +1892,17 @@
for (int i = 0; i < N; i++) {
if (mUserIds.get(i) == null) {
mUserIds.set(i, obj);
- return PackageManagerService.FIRST_APPLICATION_UID + i;
+ return Process.FIRST_APPLICATION_UID + i;
}
}
// None left?
- if (N >= PackageManagerService.MAX_APPLICATION_UIDS) {
+ if (N > (Process.LAST_APPLICATION_UID-Process.FIRST_APPLICATION_UID)) {
return -1;
}
mUserIds.add(obj);
- return PackageManagerService.FIRST_APPLICATION_UID + N;
+ return Process.FIRST_APPLICATION_UID + N;
}
public VerifierDeviceIdentity getVerifierDeviceIdentityLPw() {
@@ -2018,6 +2012,39 @@
return false;
}
+ static final void printFlags(PrintWriter pw, int val, Object[] spec) {
+ pw.print("[ ");
+ for (int i=0; i<spec.length; i+=2) {
+ int mask = (Integer)spec[i];
+ if ((val & mask) != 0) {
+ pw.print(spec[i+1]);
+ pw.print(" ");
+ }
+ }
+ pw.print("]");
+ }
+
+ static final Object[] FLAG_DUMP_SPEC = new Object[] {
+ ApplicationInfo.FLAG_SYSTEM, "SYSTEM",
+ ApplicationInfo.FLAG_DEBUGGABLE, "DEBUGGABLE",
+ ApplicationInfo.FLAG_HAS_CODE, "HAS_CODE",
+ ApplicationInfo.FLAG_PERSISTENT, "PERSISTENT",
+ ApplicationInfo.FLAG_FACTORY_TEST, "FACTORY_TEST",
+ ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING, "ALLOW_TASK_REPARENTING",
+ ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA, "ALLOW_CLEAR_USER_DATA",
+ ApplicationInfo.FLAG_UPDATED_SYSTEM_APP, "UPDATED_SYSTEM_APP",
+ ApplicationInfo.FLAG_TEST_ONLY, "TEST_ONLY",
+ ApplicationInfo.FLAG_VM_SAFE_MODE, "VM_SAFE_MODE",
+ ApplicationInfo.FLAG_ALLOW_BACKUP, "ALLOW_BACKUP",
+ ApplicationInfo.FLAG_KILL_AFTER_RESTORE, "KILL_AFTER_RESTORE",
+ ApplicationInfo.FLAG_RESTORE_ANY_VERSION, "RESTORE_ANY_VERSION",
+ ApplicationInfo.FLAG_EXTERNAL_STORAGE, "EXTERNAL_STORAGE",
+ ApplicationInfo.FLAG_LARGE_HEAP, "LARGE_HEAP",
+ ApplicationInfo.FLAG_STOPPED, "STOPPED",
+ ApplicationInfo.FLAG_FORWARD_LOCK, "FORWARD_LOCK",
+ ApplicationInfo.FLAG_CANT_SAVE_STATE, "CANT_SAVE_STATE",
+ };
+
void dumpPackagesLPr(PrintWriter pw, String packageName, DumpState dumpState) {
final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
final Date date = new Date();
@@ -2058,6 +2085,7 @@
pw.print(" nativeLibraryPath="); pw.println(ps.nativeLibraryPathString);
pw.print(" versionCode="); pw.println(ps.versionCode);
if (ps.pkg != null) {
+ pw.print(" flags="); printFlags(pw, ps.pkg.applicationInfo.flags, FLAG_DUMP_SPEC); pw.println();
pw.print(" versionName="); pw.println(ps.pkg.mVersionName);
pw.print(" dataDir="); pw.println(ps.pkg.applicationInfo.dataDir);
pw.print(" targetSdk="); pw.println(ps.pkg.applicationInfo.targetSdkVersion);
diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java
index 8f51466..ed83fbe 100644
--- a/services/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/java/com/android/server/usb/UsbDeviceManager.java
@@ -46,6 +46,7 @@
import android.os.SystemProperties;
import android.os.UEventObserver;
import android.provider.Settings;
+import android.util.Pair;
import android.util.Slog;
import java.io.File;
@@ -54,7 +55,10 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.LinkedList;
import java.util.List;
+import java.util.HashMap;
+import java.util.Map;
/**
* UsbDeviceManager manages USB state in device mode.
@@ -88,6 +92,8 @@
// which need debouncing.
private static final int UPDATE_DELAY = 1000;
+ private static final String BOOT_MODE_PROPERTY = "ro.bootmode";
+
private UsbHandler mHandler;
private boolean mBootCompleted;
@@ -98,6 +104,7 @@
private final boolean mHasUsbAccessory;
private boolean mUseUsbNotification;
private boolean mAdbEnabled;
+ private Map<String, List<Pair<String, String>>> mOemModeMap;
private class AdbSettingsObserver extends ContentObserver {
public AdbSettingsObserver() {
@@ -138,6 +145,8 @@
mHasUsbAccessory = pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY);
initRndisAddress();
+ readOemUsbOverrideConfig();
+
// create a thread for our Handler
HandlerThread thread = new HandlerThread("UsbDeviceManager",
Process.THREAD_PRIORITY_BACKGROUND);
@@ -259,6 +268,10 @@
// persist.sys.usb.config should never be unset. But if it is, set it to "adb"
// so we have a chance of debugging what happened.
mDefaultFunctions = SystemProperties.get("persist.sys.usb.config", "adb");
+
+ // Check if USB mode needs to be overridden depending on OEM specific bootmode.
+ mDefaultFunctions = processOemUsbOverride(mDefaultFunctions);
+
// sanity check the sys.usb.config system property
// this may be necessary if we crashed while switching USB configurations
String config = SystemProperties.get("sys.usb.config", "none");
@@ -381,7 +394,11 @@
}
private void setEnabledFunctions(String functions, boolean makeDefault) {
- if (functions != null && makeDefault) {
+
+ // Do not update persystent.sys.usb.config if the device is booted up
+ // with OEM specific mode.
+ if (functions != null && makeDefault && !needsOemUsbOverride()) {
+
if (mAdbEnabled) {
functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB);
} else {
@@ -410,6 +427,10 @@
if (functions == null) {
functions = mDefaultFunctions;
}
+
+ // Override with bootmode specific usb mode if needed
+ functions = processOemUsbOverride(functions);
+
if (mAdbEnabled) {
functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB);
} else {
@@ -671,6 +692,53 @@
}
}
+ private void readOemUsbOverrideConfig() {
+ String[] configList = mContext.getResources().getStringArray(
+ com.android.internal.R.array.config_oemUsbModeOverride);
+
+ if (configList != null) {
+ for (String config: configList) {
+ String[] items = config.split(":");
+ if (items.length == 3) {
+ if (mOemModeMap == null) {
+ mOemModeMap = new HashMap<String, List<Pair<String, String>>>();
+ }
+ List overrideList = mOemModeMap.get(items[0]);
+ if (overrideList == null) {
+ overrideList = new LinkedList<Pair<String, String>>();
+ mOemModeMap.put(items[0], overrideList);
+ }
+ overrideList.add(new Pair<String, String>(items[1], items[2]));
+ }
+ }
+ }
+ }
+
+ private boolean needsOemUsbOverride() {
+ if (mOemModeMap == null) return false;
+
+ String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
+ return (mOemModeMap.get(bootMode) != null) ? true : false;
+ }
+
+ private String processOemUsbOverride(String usbFunctions) {
+ if ((usbFunctions == null) || (mOemModeMap == null)) return usbFunctions;
+
+ String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
+
+ List<Pair<String, String>> overrides = mOemModeMap.get(bootMode);
+ if (overrides != null) {
+ for (Pair<String, String> pair: overrides) {
+ if (pair.first.equals(usbFunctions)) {
+ Slog.d(TAG, "OEM USB override: " + pair.first + " ==> " + pair.second);
+ return pair.second;
+ }
+ }
+ }
+ // return passed in functions as is.
+ return usbFunctions;
+ }
+
public void dump(FileDescriptor fd, PrintWriter pw) {
if (mHandler != null) {
mHandler.dump(fd, pw);
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 04c1c98..3b5ec03 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -250,6 +250,7 @@
private static final String SYSTEM_SECURE = "ro.secure";
private static final String SYSTEM_DEBUGGABLE = "ro.debuggable";
+ private static final String SYSTEM_HEADLESS = "ro.config.headless";
/**
* Condition waited on by {@link #reenableKeyguard} to know the call to
@@ -259,6 +260,8 @@
*/
private boolean mKeyguardDisabled = false;
+ private final boolean mHeadless;
+
private static final int ALLOW_DISABLE_YES = 1;
private static final int ALLOW_DISABLE_NO = 0;
private static final int ALLOW_DISABLE_UNKNOWN = -1; // check with DevicePolicyManager
@@ -789,6 +792,7 @@
mAllowBootMessages = showBootMsgs;
mLimitedAlphaCompositing = context.getResources().getBoolean(
com.android.internal.R.bool.config_sf_limitedAlpha);
+ mHeadless = "1".equals(SystemProperties.get(SYSTEM_HEADLESS, "0"));
mPowerManager = pm;
mPowerManager.setPolicy(mPolicy);
@@ -4889,7 +4893,7 @@
public void performBootTimeout() {
synchronized(mWindowMap) {
- if (mDisplayEnabled) {
+ if (mDisplayEnabled || mHeadless) {
return;
}
Slog.w(TAG, "***** BOOT TIMEOUT: forcing display enabled");
@@ -5057,6 +5061,8 @@
// TODO: more accounting of which pid(s) turned it on, keep count,
// only allow disables from pids which have count on, etc.
public void showStrictModeViolation(boolean on) {
+ if (mHeadless) return;
+
int pid = Binder.getCallingPid();
synchronized(mWindowMap) {
// Ignoring requests to enable the red border from clients
diff --git a/services/jni/Android.mk b/services/jni/Android.mk
index 6fa5dfa..c63b84df 100644
--- a/services/jni/Android.mk
+++ b/services/jni/Android.mk
@@ -9,6 +9,7 @@
com_android_server_InputWindowHandle.cpp \
com_android_server_LightsService.cpp \
com_android_server_PowerManagerService.cpp \
+ com_android_server_SerialService.cpp \
com_android_server_SystemServer.cpp \
com_android_server_UsbDeviceManager.cpp \
com_android_server_UsbHostManager.cpp \
diff --git a/services/jni/com_android_server_BatteryService.cpp b/services/jni/com_android_server_BatteryService.cpp
index 1cadc4e..ca6f206 100644
--- a/services/jni/com_android_server_BatteryService.cpp
+++ b/services/jni/com_android_server_BatteryService.cpp
@@ -233,75 +233,75 @@
DIR* dir = opendir(POWER_SUPPLY_PATH);
if (dir == NULL) {
ALOGE("Could not open %s\n", POWER_SUPPLY_PATH);
- return -1;
- }
- while ((entry = readdir(dir))) {
- const char* name = entry->d_name;
+ } else {
+ while ((entry = readdir(dir))) {
+ const char* name = entry->d_name;
- // ignore "." and ".."
- if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
- continue;
- }
-
- char buf[20];
- // Look for "type" file in each subdirectory
- snprintf(path, sizeof(path), "%s/%s/type", POWER_SUPPLY_PATH, name);
- int length = readFromFile(path, buf, sizeof(buf));
- if (length > 0) {
- if (buf[length - 1] == '\n')
- buf[length - 1] = 0;
-
- if (strcmp(buf, "Mains") == 0) {
- snprintf(path, sizeof(path), "%s/%s/online", POWER_SUPPLY_PATH, name);
- if (access(path, R_OK) == 0)
- gPaths.acOnlinePath = strdup(path);
+ // ignore "." and ".."
+ if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
+ continue;
}
- else if (strcmp(buf, "USB") == 0) {
- snprintf(path, sizeof(path), "%s/%s/online", POWER_SUPPLY_PATH, name);
- if (access(path, R_OK) == 0)
- gPaths.usbOnlinePath = strdup(path);
- }
- else if (strcmp(buf, "Battery") == 0) {
- snprintf(path, sizeof(path), "%s/%s/status", POWER_SUPPLY_PATH, name);
- if (access(path, R_OK) == 0)
- gPaths.batteryStatusPath = strdup(path);
- snprintf(path, sizeof(path), "%s/%s/health", POWER_SUPPLY_PATH, name);
- if (access(path, R_OK) == 0)
- gPaths.batteryHealthPath = strdup(path);
- snprintf(path, sizeof(path), "%s/%s/present", POWER_SUPPLY_PATH, name);
- if (access(path, R_OK) == 0)
- gPaths.batteryPresentPath = strdup(path);
- snprintf(path, sizeof(path), "%s/%s/capacity", POWER_SUPPLY_PATH, name);
- if (access(path, R_OK) == 0)
- gPaths.batteryCapacityPath = strdup(path);
- snprintf(path, sizeof(path), "%s/%s/voltage_now", POWER_SUPPLY_PATH, name);
- if (access(path, R_OK) == 0) {
- gPaths.batteryVoltagePath = strdup(path);
- // voltage_now is in microvolts, not millivolts
- gVoltageDivisor = 1000;
- } else {
- snprintf(path, sizeof(path), "%s/%s/batt_vol", POWER_SUPPLY_PATH, name);
+ char buf[20];
+ // Look for "type" file in each subdirectory
+ snprintf(path, sizeof(path), "%s/%s/type", POWER_SUPPLY_PATH, name);
+ int length = readFromFile(path, buf, sizeof(buf));
+ if (length > 0) {
+ if (buf[length - 1] == '\n')
+ buf[length - 1] = 0;
+
+ if (strcmp(buf, "Mains") == 0) {
+ snprintf(path, sizeof(path), "%s/%s/online", POWER_SUPPLY_PATH, name);
if (access(path, R_OK) == 0)
+ gPaths.acOnlinePath = strdup(path);
+ }
+ else if (strcmp(buf, "USB") == 0) {
+ snprintf(path, sizeof(path), "%s/%s/online", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0)
+ gPaths.usbOnlinePath = strdup(path);
+ }
+ else if (strcmp(buf, "Battery") == 0) {
+ snprintf(path, sizeof(path), "%s/%s/status", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0)
+ gPaths.batteryStatusPath = strdup(path);
+ snprintf(path, sizeof(path), "%s/%s/health", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0)
+ gPaths.batteryHealthPath = strdup(path);
+ snprintf(path, sizeof(path), "%s/%s/present", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0)
+ gPaths.batteryPresentPath = strdup(path);
+ snprintf(path, sizeof(path), "%s/%s/capacity", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0)
+ gPaths.batteryCapacityPath = strdup(path);
+
+ snprintf(path, sizeof(path), "%s/%s/voltage_now", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0) {
gPaths.batteryVoltagePath = strdup(path);
- }
+ // voltage_now is in microvolts, not millivolts
+ gVoltageDivisor = 1000;
+ } else {
+ snprintf(path, sizeof(path), "%s/%s/batt_vol", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0)
+ gPaths.batteryVoltagePath = strdup(path);
+ }
- snprintf(path, sizeof(path), "%s/%s/temp", POWER_SUPPLY_PATH, name);
- if (access(path, R_OK) == 0) {
- gPaths.batteryTemperaturePath = strdup(path);
- } else {
- snprintf(path, sizeof(path), "%s/%s/batt_temp", POWER_SUPPLY_PATH, name);
- if (access(path, R_OK) == 0)
+ snprintf(path, sizeof(path), "%s/%s/temp", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0) {
gPaths.batteryTemperaturePath = strdup(path);
- }
+ } else {
+ snprintf(path, sizeof(path), "%s/%s/batt_temp", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0)
+ gPaths.batteryTemperaturePath = strdup(path);
+ }
- snprintf(path, sizeof(path), "%s/%s/technology", POWER_SUPPLY_PATH, name);
- if (access(path, R_OK) == 0)
- gPaths.batteryTechnologyPath = strdup(path);
+ snprintf(path, sizeof(path), "%s/%s/technology", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0)
+ gPaths.batteryTechnologyPath = strdup(path);
+ }
}
}
+ closedir(dir);
}
- closedir(dir);
if (!gPaths.acOnlinePath)
ALOGE("acOnlinePath not found");
diff --git a/services/jni/com_android_server_SerialService.cpp b/services/jni/com_android_server_SerialService.cpp
new file mode 100644
index 0000000..b889b78
--- /dev/null
+++ b/services/jni/com_android_server_SerialService.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SerialServiceJNI"
+#include "utils/Log.h"
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+namespace android
+{
+
+static struct parcel_file_descriptor_offsets_t
+{
+ jclass mClass;
+ jmethodID mConstructor;
+} gParcelFileDescriptorOffsets;
+
+static jobject android_server_SerialService_open(JNIEnv *env, jobject thiz, jstring path)
+{
+ const char *pathStr = env->GetStringUTFChars(path, NULL);
+
+ int fd = open(pathStr, O_RDWR | O_NOCTTY);
+ if (fd < 0) {
+ ALOGE("could not open %s", pathStr);
+ env->ReleaseStringUTFChars(path, pathStr);
+ return NULL;
+ }
+ env->ReleaseStringUTFChars(path, pathStr);
+
+ jobject fileDescriptor = jniCreateFileDescriptor(env, fd);
+ if (fileDescriptor == NULL) {
+ return NULL;
+ }
+ return env->NewObject(gParcelFileDescriptorOffsets.mClass,
+ gParcelFileDescriptorOffsets.mConstructor, fileDescriptor);
+}
+
+
+static JNINativeMethod method_table[] = {
+ { "native_open", "(Ljava/lang/String;)Landroid/os/ParcelFileDescriptor;",
+ (void*)android_server_SerialService_open },
+};
+
+int register_android_server_SerialService(JNIEnv *env)
+{
+ jclass clazz = env->FindClass("com/android/server/SerialService");
+ if (clazz == NULL) {
+ ALOGE("Can't find com/android/server/SerialService");
+ return -1;
+ }
+
+ clazz = env->FindClass("android/os/ParcelFileDescriptor");
+ LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.ParcelFileDescriptor");
+ gParcelFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
+ gParcelFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "(Ljava/io/FileDescriptor;)V");
+ LOG_FATAL_IF(gParcelFileDescriptorOffsets.mConstructor == NULL,
+ "Unable to find constructor for android.os.ParcelFileDescriptor");
+
+ return jniRegisterNativeMethods(env, "com/android/server/SerialService",
+ method_table, NELEM(method_table));
+}
+
+};
diff --git a/services/jni/onload.cpp b/services/jni/onload.cpp
index c7beb5f..423ebd1 100644
--- a/services/jni/onload.cpp
+++ b/services/jni/onload.cpp
@@ -27,6 +27,7 @@
int register_android_server_InputManager(JNIEnv* env);
int register_android_server_LightsService(JNIEnv* env);
int register_android_server_PowerManagerService(JNIEnv* env);
+int register_android_server_SerialService(JNIEnv* env);
int register_android_server_UsbDeviceManager(JNIEnv* env);
int register_android_server_UsbHostManager(JNIEnv* env);
int register_android_server_VibratorService(JNIEnv* env);
@@ -49,6 +50,7 @@
ALOG_ASSERT(env, "Could not retrieve the env!");
register_android_server_PowerManagerService(env);
+ register_android_server_SerialService(env);
register_android_server_InputApplicationHandle(env);
register_android_server_InputWindowHandle(env);
register_android_server_InputManager(env);
diff --git a/telephony/java/com/android/internal/telephony/BaseCommands.java b/telephony/java/com/android/internal/telephony/BaseCommands.java
index 893d7a8..35cdf9bd 100644
--- a/telephony/java/com/android/internal/telephony/BaseCommands.java
+++ b/telephony/java/com/android/internal/telephony/BaseCommands.java
@@ -715,4 +715,7 @@
"' lteOnCdmaProductType='" + sLteOnCdmaProductType + "'");
return retVal;
}
+
+ @Override
+ public void testingEmergencyCall() {}
}
diff --git a/telephony/java/com/android/internal/telephony/CallTracker.java b/telephony/java/com/android/internal/telephony/CallTracker.java
index 31f9e18..958481c 100644
--- a/telephony/java/com/android/internal/telephony/CallTracker.java
+++ b/telephony/java/com/android/internal/telephony/CallTracker.java
@@ -19,6 +19,8 @@
import android.os.AsyncResult;
import android.os.Handler;
import android.os.Message;
+import android.os.SystemProperties;
+import android.text.TextUtils;
import android.util.Log;
import com.android.internal.telephony.CommandException;
@@ -116,6 +118,48 @@
return pendingOperations == 0;
}
+ /**
+ * Routine called from dial to check if the number is a test Emergency number
+ * and if so remap the number. This allows a short emergency number to be remapped
+ * to a regular number for testing how the frameworks handles emergency numbers
+ * without actually calling an emergency number.
+ *
+ * This is not a full test and is not a substitute for testing real emergency
+ * numbers but can be useful.
+ *
+ * To use this feature set a system property ril.test.emergencynumber to a pair of
+ * numbers separated by a colon. If the first number matches the number parameter
+ * this routine returns the second number. Example:
+ *
+ * ril.test.emergencynumber=112:1-123-123-45678
+ *
+ * To test Dial 112 take call then hang up on MO device to enter ECM
+ * see RIL#processSolicited RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND
+ *
+ * @param number to test if it should be remapped
+ * @return the same number or the remapped number.
+ */
+ protected String checkForTestEmergencyNumber(String dialString) {
+ String testEn = SystemProperties.get("ril.test.emergencynumber");
+ if (DBG_POLL) {
+ log("checkForTestEmergencyNumber: dialString=" + dialString +
+ " testEn=" + testEn);
+ }
+ if (!TextUtils.isEmpty(testEn)) {
+ String values[] = testEn.split(":");
+ log("checkForTestEmergencyNumber: values.length=" + values.length);
+ if (values.length == 2) {
+ if (values[0].equals(
+ android.telephony.PhoneNumberUtils.stripSeparators(dialString))) {
+ cm.testingEmergencyCall();
+ log("checkForTestEmergencyNumber: remap " +
+ dialString + " to " + values[1]);
+ dialString = values[1];
+ }
+ }
+ }
+ return dialString;
+ }
//***** Overridden from Handler
public abstract void handleMessage (Message msg);
diff --git a/telephony/java/com/android/internal/telephony/CommandsInterface.java b/telephony/java/com/android/internal/telephony/CommandsInterface.java
index a0efab20..f7757b3 100644
--- a/telephony/java/com/android/internal/telephony/CommandsInterface.java
+++ b/telephony/java/com/android/internal/telephony/CommandsInterface.java
@@ -1571,4 +1571,9 @@
* @param response a callback message with the String response in the obj field
*/
public void requestIsimAuthentication(String nonce, Message response);
+
+ /**
+ * Notifiy that we are testing an emergency call
+ */
+ public void testingEmergencyCall();
}
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index f587fe1..5afc1f3 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -60,6 +60,7 @@
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* {@hide}
@@ -232,6 +233,9 @@
Object mLastNITZTimeInfo;
+ // When we are testing emergency calls
+ AtomicBoolean mTestingEmergencyCall = new AtomicBoolean(false);
+
//***** Events
static final int EVENT_SEND = 1;
@@ -2213,7 +2217,16 @@
case RIL_REQUEST_GET_IMSI: ret = responseString(p); break;
case RIL_REQUEST_HANGUP: ret = responseVoid(p); break;
case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND: ret = responseVoid(p); break;
- case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND: ret = responseVoid(p); break;
+ case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND: {
+ if (mTestingEmergencyCall.getAndSet(false)) {
+ if (mEmergencyCallbackModeRegistrant != null) {
+ riljLog("testing emergency call, notify ECM Registrants");
+ mEmergencyCallbackModeRegistrant.notifyRegistrant();
+ }
+ }
+ ret = responseVoid(p);
+ break;
+ }
case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE: ret = responseVoid(p); break;
case RIL_REQUEST_CONFERENCE: ret = responseVoid(p); break;
case RIL_REQUEST_UDUB: ret = responseVoid(p); break;
@@ -3014,6 +3027,11 @@
num = p.readInt();
response = new ArrayList<DriverCall>(num);
+ if (RILJ_LOGV) {
+ riljLog("responseCallList: num=" + num +
+ " mEmergencyCallbackModeRegistrant=" + mEmergencyCallbackModeRegistrant +
+ " mTestingEmergencyCall=" + mTestingEmergencyCall.get());
+ }
for (int i = 0 ; i < num ; i++) {
dc = new DriverCall();
@@ -3065,6 +3083,14 @@
Collections.sort(response);
+ if ((num == 0) && mTestingEmergencyCall.getAndSet(false)) {
+ if (mEmergencyCallbackModeRegistrant != null) {
+ riljLog("responseCallList: call ended, testing emergency call," +
+ " notify ECM Registrants");
+ mEmergencyCallbackModeRegistrant.notifyRegistrant();
+ }
+ }
+
return response;
}
@@ -3791,4 +3817,13 @@
send(rr);
}
+
+ /* (non-Javadoc)
+ * @see com.android.internal.telephony.BaseCommands#testingEmergencyCall()
+ */
+ @Override
+ public void testingEmergencyCall() {
+ if (RILJ_LOGD) riljLog("testingEmergencyCall");
+ mTestingEmergencyCall.set(true);
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
index 83efc51..f918dce 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
@@ -210,7 +210,8 @@
return dialThreeWay(dialString);
}
- pendingMO = new CdmaConnection(phone.getContext(), dialString, this, foregroundCall);
+ pendingMO = new CdmaConnection(phone.getContext(), checkForTestEmergencyNumber(dialString),
+ this, foregroundCall);
hangupPendingMO = false;
if (pendingMO.address == null || pendingMO.address.length() == 0
@@ -259,7 +260,7 @@
// Attach the new connection to foregroundCall
pendingMO = new CdmaConnection(phone.getContext(),
- dialString, this, foregroundCall);
+ checkForTestEmergencyNumber(dialString), this, foregroundCall);
cm.sendCDMAFeatureCode(pendingMO.address,
obtainMessage(EVENT_THREE_WAY_DIAL_L2_RESULT_CDMA));
return pendingMO;
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java
index 06f310c..425afe6 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java
@@ -198,7 +198,8 @@
throw new CallStateException("cannot dial in current state");
}
- pendingMO = new GsmConnection(phone.getContext(), dialString, this, foregroundCall);
+ pendingMO = new GsmConnection(phone.getContext(), checkForTestEmergencyNumber(dialString),
+ this, foregroundCall);
hangupPendingMO = false;
if (pendingMO.address == null || pendingMO.address.length() == 0
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index 0b4fc51..674c0b7 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -333,6 +333,12 @@
throw new UnsupportedOperationException();
}
+ /** @hide */
+ @Override
+ public boolean bindService(Intent service, ServiceConnection conn, int flags, int userId) {
+ throw new UnsupportedOperationException();
+ }
+
@Override
public void unbindService(ServiceConnection conn) {
throw new UnsupportedOperationException();
diff --git a/tests/BiDiTests/res/layout/grid_layout_code.xml b/tests/BiDiTests/res/layout/grid_layout_code.xml
new file mode 100644
index 0000000..87a0ec0
--- /dev/null
+++ b/tests/BiDiTests/res/layout/grid_layout_code.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/grid_layout_code"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+</FrameLayout>
\ No newline at end of file
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
index 4d7ace1..c5a1235 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
@@ -111,6 +111,8 @@
addItem(result, "Grid LTR", BiDiTestGridLayoutLtr.class, R.id.grid_layout_ltr);
addItem(result, "Grid RTL", BiDiTestGridLayoutRtl.class, R.id.grid_layout_rtl);
addItem(result, "Grid LOC", BiDiTestGridLayoutLocale.class, R.id.grid_layout_locale);
+ addItem(result, "Grid C-LTR", BiDiTestGridLayoutCodeLtr.class, R.id.grid_layout_code);
+ addItem(result, "Grid C-RTL", BiDiTestGridLayoutCodeRtl.class, R.id.grid_layout_code);
addItem(result, "Frame LTR", BiDiTestFrameLayoutLtr.class, R.id.frame_layout_ltr);
addItem(result, "Frame RTL", BiDiTestFrameLayoutRtl.class, R.id.frame_layout_rtl);
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutCodeLtr.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutCodeLtr.java
new file mode 100644
index 0000000..859b8fb
--- /dev/null
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutCodeLtr.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bidi;
+
+import android.app.Fragment;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.GridLayout;
+
+import android.widget.*;
+
+import static android.text.InputType.*;
+import static android.widget.GridLayout.*;
+
+public class BiDiTestGridLayoutCodeLtr extends Fragment {
+
+ private FrameLayout currentView;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ currentView = (FrameLayout) inflater.inflate(R.layout.grid_layout_code, container, false);
+ return currentView;
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ currentView.addView(create(currentView.getContext()));
+ }
+
+ public static View create(Context context) {
+ GridLayout layout = new GridLayout(context);
+ layout.setUseDefaultMargins(true);
+ layout.setAlignmentMode(ALIGN_BOUNDS);
+ layout.setRowOrderPreserved(false);
+ layout.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
+
+ Spec row1 = spec(0);
+ Spec row2 = spec(1);
+ Spec row3 = spec(2, BASELINE);
+ Spec row4 = spec(3, BASELINE);
+ Spec row5 = spec(2, 3, FILL); // allow the last two rows to overlap the middle two
+ Spec row6 = spec(5);
+ Spec row7 = spec(6);
+
+ Spec col1a = spec(0, 4, CENTER);
+ Spec col1b = spec(0, 4, START);
+ Spec col1c = spec(0, END);
+ Spec col2 = spec(1, START);
+ Spec col3 = spec(2, FILL);
+ Spec col4a = spec(3);
+ Spec col4b = spec(3, FILL);
+
+ {
+ TextView c = new TextView(context);
+ c.setTextSize(32);
+ c.setText("Email setup");
+ layout.addView(c, new GridLayout.LayoutParams(row1, col1a));
+ }
+ {
+ TextView c = new TextView(context);
+ c.setTextSize(16);
+ c.setText("You can configure email in just a few steps:");
+ layout.addView(c, new GridLayout.LayoutParams(row2, col1b));
+ }
+ {
+ TextView c = new TextView(context);
+ c.setText("Email address:");
+ layout.addView(c, new GridLayout.LayoutParams(row3, col1c));
+ }
+ {
+ EditText c = new EditText(context);
+ c.setEms(10);
+ c.setInputType(TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
+ layout.addView(c, new GridLayout.LayoutParams(row3, col2));
+ }
+ {
+ TextView c = new TextView(context);
+ c.setText("Password:");
+ layout.addView(c, new GridLayout.LayoutParams(row4, col1c));
+ }
+ {
+ TextView c = new EditText(context);
+ c.setEms(8);
+ c.setInputType(TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_PASSWORD);
+ layout.addView(c, new GridLayout.LayoutParams(row4, col2));
+ }
+ {
+ Space c = new Space(context);
+ layout.addView(c, new GridLayout.LayoutParams(row5, col3));
+ }
+ {
+ Button c = new Button(context);
+ c.setText("Manual setup");
+ layout.addView(c, new GridLayout.LayoutParams(row6, col4a));
+ }
+ {
+ Button c = new Button(context);
+ c.setText("Next");
+ layout.addView(c, new GridLayout.LayoutParams(row7, col4b));
+ }
+
+ return layout;
+ }
+}
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutCodeRtl.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutCodeRtl.java
new file mode 100644
index 0000000..fac8c950
--- /dev/null
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutCodeRtl.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bidi;
+
+import android.app.Fragment;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.*;
+
+import static android.text.InputType.*;
+import static android.widget.GridLayout.*;
+
+public class BiDiTestGridLayoutCodeRtl extends Fragment {
+
+ private FrameLayout currentView;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ currentView = (FrameLayout) inflater.inflate(R.layout.grid_layout_code, container, false);
+ return currentView;
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ currentView.addView(create(currentView.getContext()));
+ }
+
+ public static View create(Context context) {
+ GridLayout layout = new GridLayout(context);
+ layout.setUseDefaultMargins(true);
+ layout.setAlignmentMode(ALIGN_BOUNDS);
+ layout.setRowOrderPreserved(false);
+ layout.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
+
+ Spec row1 = spec(0);
+ Spec row2 = spec(1);
+ Spec row3 = spec(2, BASELINE);
+ Spec row4 = spec(3, BASELINE);
+ Spec row5 = spec(2, 3, FILL); // allow the last two rows to overlap the middle two
+ Spec row6 = spec(5);
+ Spec row7 = spec(6);
+
+ Spec col1a = spec(0, 4, CENTER);
+ Spec col1b = spec(0, 4, START);
+ Spec col1c = spec(0, END);
+ Spec col2 = spec(1, START);
+ Spec col3 = spec(2, FILL);
+ Spec col4a = spec(3);
+ Spec col4b = spec(3, FILL);
+
+ {
+ TextView c = new TextView(context);
+ c.setTextSize(32);
+ c.setText("Email setup");
+ layout.addView(c, new GridLayout.LayoutParams(row1, col1a));
+ }
+ {
+ TextView c = new TextView(context);
+ c.setTextSize(16);
+ c.setText("You can configure email in just a few steps:");
+ layout.addView(c, new GridLayout.LayoutParams(row2, col1b));
+ }
+ {
+ TextView c = new TextView(context);
+ c.setText("Email address:");
+ layout.addView(c, new GridLayout.LayoutParams(row3, col1c));
+ }
+ {
+ EditText c = new EditText(context);
+ c.setEms(10);
+ c.setInputType(TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
+ layout.addView(c, new GridLayout.LayoutParams(row3, col2));
+ }
+ {
+ TextView c = new TextView(context);
+ c.setText("Password:");
+ layout.addView(c, new GridLayout.LayoutParams(row4, col1c));
+ }
+ {
+ TextView c = new EditText(context);
+ c.setEms(8);
+ c.setInputType(TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_PASSWORD);
+ layout.addView(c, new GridLayout.LayoutParams(row4, col2));
+ }
+ {
+ Space c = new Space(context);
+ layout.addView(c, new GridLayout.LayoutParams(row5, col3));
+ }
+ {
+ Button c = new Button(context);
+ c.setText("Manual setup");
+ layout.addView(c, new GridLayout.LayoutParams(row6, col4a));
+ }
+ {
+ Button c = new Button(context);
+ c.setText("Next");
+ layout.addView(c, new GridLayout.LayoutParams(row7, col4b));
+ }
+
+ return layout;
+ }
+}
diff --git a/tests/SerialChat/Android.mk b/tests/SerialChat/Android.mk
new file mode 100644
index 0000000..a534e1a
--- /dev/null
+++ b/tests/SerialChat/Android.mk
@@ -0,0 +1,26 @@
+#
+# Copyright (C) 2011 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := SerialChat
+
+include $(BUILD_PACKAGE)
diff --git a/tests/SerialChat/AndroidManifest.xml b/tests/SerialChat/AndroidManifest.xml
new file mode 100644
index 0000000..0efdb58
--- /dev/null
+++ b/tests/SerialChat/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.serialchat">
+
+ <uses-permission android:name="android.permission.SERIAL_PORT"/>
+
+ <application android:label="Serial Chat">
+ <activity android:name="SerialChat" android:label="Serial Chat">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/SerialChat/res/layout/serial_chat.xml b/tests/SerialChat/res/layout/serial_chat.xml
new file mode 100644
index 0000000..596ecbf
--- /dev/null
+++ b/tests/SerialChat/res/layout/serial_chat.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ >
+
+ <ScrollView android:id="@+id/scroll"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1"
+ >
+ <TextView android:id="@+id/log"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="25dp"
+ android:textSize="12sp"
+ android:textColor="#ffffffff"
+ />
+ </ScrollView>
+
+ <EditText android:id="@+id/message"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:capitalize="sentences"
+ android:autoText="true"
+ android:singleLine="true"
+ />
+
+</LinearLayout>
+
+
diff --git a/tests/SerialChat/src/com/android/serialchat/SerialChat.java b/tests/SerialChat/src/com/android/serialchat/SerialChat.java
new file mode 100644
index 0000000..faec312
--- /dev/null
+++ b/tests/SerialChat/src/com/android/serialchat/SerialChat.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.serialchat;
+
+import android.app.Activity;
+import android.content.Context;
+import android.hardware.SerialManager;
+import android.hardware.SerialPort;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.ParcelFileDescriptor;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.inputmethod.EditorInfo;
+import android.util.Log;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import java.nio.ByteBuffer;
+import java.io.IOException;
+
+public class SerialChat extends Activity implements Runnable, TextView.OnEditorActionListener {
+
+ private static final String TAG = "SerialChat";
+
+ private TextView mLog;
+ private EditText mEditText;
+ private ByteBuffer mInputBuffer;
+ private ByteBuffer mOutputBuffer;
+ private SerialManager mSerialManager;
+ private SerialPort mSerialPort;
+ private boolean mPermissionRequestPending;
+
+ private static final int MESSAGE_LOG = 1;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mSerialManager = (SerialManager)getSystemService(Context.SERIAL_SERVICE);
+ setContentView(R.layout.serial_chat);
+ mLog = (TextView)findViewById(R.id.log);
+ mEditText = (EditText)findViewById(R.id.message);
+ mEditText.setOnEditorActionListener(this);
+
+ if (false) {
+ mInputBuffer = ByteBuffer.allocateDirect(1024);
+ mOutputBuffer = ByteBuffer.allocateDirect(1024);
+ } else {
+ mInputBuffer = ByteBuffer.allocate(1024);
+ mOutputBuffer = ByteBuffer.allocate(1024);
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ String[] ports = mSerialManager.getSerialPorts();
+ if (ports != null && ports.length > 0) {
+ try {
+ mSerialPort = mSerialManager.openSerialPort(ports[0], 115200);
+ if (mSerialPort != null) {
+ new Thread(this).start();
+ }
+ } catch (IOException e) {
+ }
+ }
+
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+
+ }
+
+ @Override
+ public void onDestroy() {
+ if (mSerialPort != null) {
+ try {
+ mSerialPort.close();
+ } catch (IOException e) {
+ }
+ mSerialPort = null;
+ }
+ super.onDestroy();
+ }
+
+ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+ if (/* actionId == EditorInfo.IME_ACTION_DONE && */ mSerialPort != null) {
+ try {
+ String text = v.getText().toString();
+ Log.d(TAG, "write: " + text);
+ byte[] bytes = text.getBytes();
+ mOutputBuffer.clear();
+ mOutputBuffer.put(bytes);
+ mSerialPort.write(mOutputBuffer, bytes.length);
+ } catch (IOException e) {
+ Log.e(TAG, "write failed", e);
+ }
+ v.setText("");
+ return true;
+ }
+ Log.d(TAG, "onEditorAction " + actionId + " event: " + event);
+ return false;
+ }
+
+ public void run() {
+ Log.d(TAG, "run");
+ int ret = 0;
+ byte[] buffer = new byte[1024];
+ while (ret >= 0) {
+ try {
+ Log.d(TAG, "calling read");
+ mInputBuffer.clear();
+ ret = mSerialPort.read(mInputBuffer);
+ Log.d(TAG, "read returned " + ret);
+ mInputBuffer.get(buffer, 0, ret);
+ } catch (IOException e) {
+ Log.e(TAG, "read failed", e);
+ break;
+ }
+
+ if (ret > 0) {
+ Message m = Message.obtain(mHandler, MESSAGE_LOG);
+ String text = new String(buffer, 0, ret);
+ Log.d(TAG, "chat: " + text);
+ m.obj = text;
+ mHandler.sendMessage(m);
+ }
+ }
+ Log.d(TAG, "thread out");
+ }
+
+ Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MESSAGE_LOG:
+ mLog.setText(mLog.getText() + (String)msg.obj);
+ break;
+ }
+ }
+ };
+}
+
+
diff --git a/tools/aidl/AST.cpp b/tools/aidl/AST.cpp
index 752ef7c..bfa6765 100755
--- a/tools/aidl/AST.cpp
+++ b/tools/aidl/AST.cpp
@@ -111,6 +111,21 @@
fprintf(to, "%s", this->value.c_str());
}
+StringLiteralExpression::StringLiteralExpression(const string& v)
+ :value(v)
+{
+}
+
+StringLiteralExpression::~StringLiteralExpression()
+{
+}
+
+void
+StringLiteralExpression::Write(FILE* to)
+{
+ fprintf(to, "\"%s\"", this->value.c_str());
+}
+
Variable::Variable()
:type(NULL),
name(),
@@ -277,6 +292,17 @@
{
}
+MethodCall::MethodCall(const string& n, int argc = 0, ...)
+ :obj(NULL),
+ clazz(NULL),
+ name(n)
+{
+ va_list args;
+ va_start(args, argc);
+ init(argc, args);
+ va_end(args);
+}
+
MethodCall::MethodCall(Expression* o, const string& n)
:obj(o),
clazz(NULL),
@@ -367,11 +393,29 @@
{
}
+NewExpression::NewExpression(Type* t, int argc = 0, ...)
+ :type(t)
+{
+ va_list args;
+ va_start(args, argc);
+ init(argc, args);
+ va_end(args);
+}
+
NewExpression::~NewExpression()
{
}
void
+NewExpression::init(int n, va_list args)
+{
+ for (int i=0; i<n; i++) {
+ Expression* expression = (Expression*)va_arg(args, void*);
+ this->arguments.push_back(expression);
+ }
+}
+
+void
NewExpression::Write(FILE* to)
{
fprintf(to, "new %s(", this->type->InstantiableName().c_str());
@@ -636,6 +680,20 @@
fprintf(to, "}\n");
}
+Break::Break()
+{
+}
+
+Break::~Break()
+{
+}
+
+void
+Break::Write(FILE* to)
+{
+ fprintf(to, "break;\n");
+}
+
Method::Method()
:ClassElement(),
modifiers(0),
@@ -678,7 +736,7 @@
fprintf(to, "%s\n", this->comment.c_str());
}
- WriteModifiers(to, this->modifiers, SCOPE_MASK | STATIC | FINAL | OVERRIDE);
+ WriteModifiers(to, this->modifiers, SCOPE_MASK | STATIC | ABSTRACT | FINAL | OVERRIDE);
if (this->returnType != NULL) {
string dim;
diff --git a/tools/aidl/AST.h b/tools/aidl/AST.h
index 3156356..ead5e7a 100755
--- a/tools/aidl/AST.h
+++ b/tools/aidl/AST.h
@@ -54,6 +54,16 @@
virtual void Write(FILE* to);
};
+// TODO: also escape the contents. not needed for now
+struct StringLiteralExpression : public Expression
+{
+ string value;
+
+ StringLiteralExpression(const string& value);
+ virtual ~StringLiteralExpression();
+ virtual void Write(FILE* to);
+};
+
struct Variable : public Expression
{
Type* type;
@@ -104,7 +114,7 @@
virtual void Write(FILE* to) = 0;
};
-struct StatementBlock
+struct StatementBlock : public Statement
{
vector<Statement*> statements;
@@ -146,6 +156,7 @@
vector<string> exceptions;
MethodCall(const string& name);
+ MethodCall(const string& name, int argc, ...);
MethodCall(Expression* obj, const string& name);
MethodCall(Type* clazz, const string& name);
MethodCall(Expression* obj, const string& name, int argc, ...);
@@ -174,8 +185,12 @@
vector<Expression*> arguments;
NewExpression(Type* type);
+ NewExpression(Type* type, int argc, ...);
virtual ~NewExpression();
virtual void Write(FILE* to);
+
+private:
+ void init(int n, va_list args);
};
struct NewArrayExpression : public Expression
@@ -292,6 +307,13 @@
virtual void Write(FILE* to);
};
+struct Break : public Statement
+{
+ Break();
+ virtual ~Break();
+ virtual void Write(FILE* to);
+};
+
struct Method : public ClassElement
{
string comment;
diff --git a/tools/aidl/Android.mk b/tools/aidl/Android.mk
index 2ad0728..77d46ab 100644
--- a/tools/aidl/Android.mk
+++ b/tools/aidl/Android.mk
@@ -17,7 +17,9 @@
search_path.cpp \
AST.cpp \
Type.cpp \
- generate_java.cpp
+ generate_java.cpp \
+ generate_java_binder.cpp \
+ generate_java_rpc.cpp
LOCAL_CFLAGS := -g
LOCAL_MODULE := aidl
diff --git a/tools/aidl/Type.cpp b/tools/aidl/Type.cpp
index 6b69864..42e1226 100755
--- a/tools/aidl/Type.cpp
+++ b/tools/aidl/Type.cpp
@@ -11,6 +11,7 @@
Type* FLOAT_TYPE;
Type* DOUBLE_TYPE;
Type* STRING_TYPE;
+Type* OBJECT_TYPE;
Type* CHAR_SEQUENCE_TYPE;
Type* TEXT_UTILS_TYPE;
Type* REMOTE_EXCEPTION_TYPE;
@@ -21,9 +22,13 @@
Type* BINDER_PROXY_TYPE;
Type* PARCEL_TYPE;
Type* PARCELABLE_INTERFACE_TYPE;
+Type* CONTEXT_TYPE;
Type* MAP_TYPE;
Type* LIST_TYPE;
Type* CLASSLOADER_TYPE;
+Type* RPC_DATA_TYPE;
+Type* RPC_ERROR_TYPE;
+Type* EVENT_FAKE_TYPE;
Expression* NULL_VALUE;
Expression* THIS_VALUE;
@@ -34,38 +39,48 @@
void
register_base_types()
{
- VOID_TYPE = new BasicType("void", "XXX", "XXX", "XXX", "XXX", "XXX");
+ VOID_TYPE = new BasicType("void",
+ "XXX", "XXX", "XXX", "XXX", "XXX",
+ "XXX", "XXX", "XXX", "XXX", "XXX");
NAMES.Add(VOID_TYPE);
BOOLEAN_TYPE = new BooleanType();
NAMES.Add(BOOLEAN_TYPE);
- BYTE_TYPE = new BasicType("byte", "writeByte", "readByte",
- "writeByteArray", "createByteArray", "readByteArray");
+ BYTE_TYPE = new BasicType("byte",
+ "writeByte", "readByte", "writeByteArray", "createByteArray", "readByteArray",
+ "putByte", "getByte", "putByteArray", "createByteArray", "getByteArray");
NAMES.Add(BYTE_TYPE);
CHAR_TYPE = new CharType();
NAMES.Add(CHAR_TYPE);
- INT_TYPE = new BasicType("int", "writeInt", "readInt",
- "writeIntArray", "createIntArray", "readIntArray");
+ INT_TYPE = new BasicType("int",
+ "writeInt", "readInt", "writeIntArray", "createIntArray", "readIntArray",
+ "putInteger", "getInteger", "putIntegerArray", "createIntegerArray", "getIntegerArray");
NAMES.Add(INT_TYPE);
- LONG_TYPE = new BasicType("long", "writeLong", "readLong",
- "writeLongArray", "createLongArray", "readLongArray");
+ LONG_TYPE = new BasicType("long",
+ "writeLong", "readLong", "writeLongArray", "createLongArray", "readLongArray",
+ "putLong", "getLong", "putLongArray", "createLongArray", "getLongArray");
NAMES.Add(LONG_TYPE);
- FLOAT_TYPE = new BasicType("float", "writeFloat", "readFloat",
- "writeFloatArray", "createFloatArray", "readFloatArray");
+ FLOAT_TYPE = new BasicType("float",
+ "writeFloat", "readFloat", "writeFloatArray", "createFloatArray", "readFloatArray",
+ "putFloat", "getFloat", "putFloatArray", "createFloatArray", "getFloatArray");
NAMES.Add(FLOAT_TYPE);
- DOUBLE_TYPE = new BasicType("double", "writeDouble", "readDouble",
- "writeDoubleArray", "createDoubleArray", "readDoubleArray");
+ DOUBLE_TYPE = new BasicType("double",
+ "writeDouble", "readDouble", "writeDoubleArray", "createDoubleArray", "readDoubleArray",
+ "putDouble", "getDouble", "putDoubleArray", "createDoubleArray", "getDoubleArray");
NAMES.Add(DOUBLE_TYPE);
STRING_TYPE = new StringType();
NAMES.Add(STRING_TYPE);
+ OBJECT_TYPE = new Type("java.lang", "Object", Type::BUILT_IN, false, false, false);
+ NAMES.Add(OBJECT_TYPE);
+
CHAR_SEQUENCE_TYPE = new CharSequenceType();
NAMES.Add(CHAR_SEQUENCE_TYPE);
@@ -75,8 +90,7 @@
LIST_TYPE = new ListType();
NAMES.Add(LIST_TYPE);
- TEXT_UTILS_TYPE = new Type("android.text", "TextUtils",
- Type::BUILT_IN, false, false);
+ TEXT_UTILS_TYPE = new Type("android.text", "TextUtils", Type::BUILT_IN, false, false, false);
NAMES.Add(TEXT_UTILS_TYPE);
REMOTE_EXCEPTION_TYPE = new RemoteExceptionType();
@@ -103,6 +117,19 @@
PARCELABLE_INTERFACE_TYPE = new ParcelableInterfaceType();
NAMES.Add(PARCELABLE_INTERFACE_TYPE);
+ CONTEXT_TYPE = new Type("android.content", "Context", Type::BUILT_IN, false, false, false);
+ NAMES.Add(CONTEXT_TYPE);
+
+ RPC_DATA_TYPE = new RpcDataType();
+ NAMES.Add(RPC_DATA_TYPE);
+
+ RPC_ERROR_TYPE = new UserDataType("com.android.athome.rpc", "RpcError",
+ true, __FILE__, __LINE__);
+ NAMES.Add(RPC_ERROR_TYPE);
+
+ EVENT_FAKE_TYPE = new Type("event", Type::BUILT_IN, false, false, false);
+ NAMES.Add(EVENT_FAKE_TYPE);
+
CLASSLOADER_TYPE = new ClassLoaderType();
NAMES.Add(CLASSLOADER_TYPE);
@@ -129,27 +156,30 @@
// ================================================================
-Type::Type(const string& name, int kind, bool canWriteToParcel, bool canBeOut)
+Type::Type(const string& name, int kind, bool canWriteToParcel, bool canWriteToRpcData,
+ bool canBeOut)
:m_package(),
m_name(name),
m_declFile(""),
m_declLine(-1),
m_kind(kind),
m_canWriteToParcel(canWriteToParcel),
+ m_canWriteToRpcData(canWriteToRpcData),
m_canBeOut(canBeOut)
{
m_qualifiedName = name;
}
Type::Type(const string& package, const string& name,
- int kind, bool canWriteToParcel, bool canBeOut,
- const string& declFile, int declLine)
+ int kind, bool canWriteToParcel, bool canWriteToRpcData,
+ bool canBeOut, const string& declFile, int declLine)
:m_package(package),
m_name(name),
m_declFile(declFile),
m_declLine(declLine),
m_kind(kind),
m_canWriteToParcel(canWriteToParcel),
+ m_canWriteToRpcData(canWriteToRpcData),
m_canBeOut(canBeOut)
{
if (package.length() > 0) {
@@ -182,6 +212,12 @@
}
string
+Type::RpcCreatorName() const
+{
+ return "";
+}
+
+string
Type::InstantiableName() const
{
return QualifiedName();
@@ -244,6 +280,26 @@
}
void
+Type::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags)
+{
+ fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
+ __FILE__, __LINE__, m_qualifiedName.c_str());
+ addTo->Add(new LiteralExpression("/* WriteToRpcData error "
+ + m_qualifiedName + " */"));
+}
+
+void
+Type::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
+ Variable** cl)
+{
+ fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
+ __FILE__, __LINE__, m_qualifiedName.c_str());
+ addTo->Add(new LiteralExpression("/* ReadFromRpcData error "
+ + m_qualifiedName + " */"));
+}
+
+void
Type::SetQualifiedName(const string& qualified)
{
m_qualifiedName = qualified;
@@ -264,29 +320,35 @@
// ================================================================
-BasicType::BasicType(const string& name, const string& marshallMethod,
- const string& unmarshallMethod,
- const string& writeArray, const string& createArray,
- const string& readArray)
- :Type(name, BUILT_IN, true, false),
- m_marshallMethod(marshallMethod),
- m_unmarshallMethod(unmarshallMethod),
- m_writeArrayMethod(writeArray),
- m_createArrayMethod(createArray),
- m_readArrayMethod(readArray)
+BasicType::BasicType(const string& name, const string& marshallParcel,
+ const string& unmarshallParcel, const string& writeArrayParcel,
+ const string& createArrayParcel, const string& readArrayParcel,
+ const string& marshallRpc, const string& unmarshallRpc,
+ const string& writeArrayRpc, const string& createArrayRpc, const string& readArrayRpc)
+ :Type(name, BUILT_IN, true, true, false),
+ m_marshallParcel(marshallParcel),
+ m_unmarshallParcel(unmarshallParcel),
+ m_writeArrayParcel(writeArrayParcel),
+ m_createArrayParcel(createArrayParcel),
+ m_readArrayParcel(readArrayParcel),
+ m_marshallRpc(marshallRpc),
+ m_unmarshallRpc(unmarshallRpc),
+ m_writeArrayRpc(writeArrayRpc),
+ m_createArrayRpc(createArrayRpc),
+ m_readArrayRpc(readArrayRpc)
{
}
void
BasicType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
{
- addTo->Add(new MethodCall(parcel, m_marshallMethod, 1, v));
+ addTo->Add(new MethodCall(parcel, m_marshallParcel, 1, v));
}
void
BasicType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
- addTo->Add(new Assignment(v, new MethodCall(parcel, m_unmarshallMethod)));
+ addTo->Add(new Assignment(v, new MethodCall(parcel, m_unmarshallParcel)));
}
bool
@@ -298,27 +360,40 @@
void
BasicType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
{
- addTo->Add(new MethodCall(parcel, m_writeArrayMethod, 1, v));
+ addTo->Add(new MethodCall(parcel, m_writeArrayParcel, 1, v));
}
void
BasicType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, Variable**)
{
- addTo->Add(new Assignment(v, new MethodCall(parcel, m_createArrayMethod)));
+ addTo->Add(new Assignment(v, new MethodCall(parcel, m_createArrayParcel)));
}
void
BasicType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
- addTo->Add(new MethodCall(parcel, m_readArrayMethod, 1, v));
+ addTo->Add(new MethodCall(parcel, m_readArrayParcel, 1, v));
}
+void
+BasicType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags)
+{
+ addTo->Add(new MethodCall(data, m_marshallRpc, 2, k, v));
+}
+
+void
+BasicType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
+ Variable** cl)
+{
+ addTo->Add(new Assignment(v, new MethodCall(data, m_unmarshallRpc, 1, k)));
+}
// ================================================================
BooleanType::BooleanType()
- :Type("boolean", BUILT_IN, true, false)
+ :Type("boolean", BUILT_IN, true, true, false)
{
}
@@ -362,11 +437,24 @@
addTo->Add(new MethodCall(parcel, "readBooleanArray", 1, v));
}
+void
+BooleanType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags)
+{
+ addTo->Add(new MethodCall(data, "putBoolean", 2, k, v));
+}
+
+void
+BooleanType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
+ Variable** cl)
+{
+ addTo->Add(new Assignment(v, new MethodCall(data, "getBoolean", 1, k)));
+}
// ================================================================
CharType::CharType()
- :Type("char", BUILT_IN, true, false)
+ :Type("char", BUILT_IN, true, true, false)
{
}
@@ -408,10 +496,24 @@
addTo->Add(new MethodCall(parcel, "readCharArray", 1, v));
}
+void
+CharType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags)
+{
+ addTo->Add(new MethodCall(data, "putChar", 2, k, v));
+}
+
+void
+CharType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
+ Variable** cl)
+{
+ addTo->Add(new Assignment(v, new MethodCall(data, "getChar", 1, k)));
+}
+
// ================================================================
StringType::StringType()
- :Type("java.lang", "String", BUILT_IN, true, false)
+ :Type("java.lang", "String", BUILT_IN, true, true, false)
{
}
@@ -458,10 +560,24 @@
addTo->Add(new MethodCall(parcel, "readStringArray", 1, v));
}
+void
+StringType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags)
+{
+ addTo->Add(new MethodCall(data, "putString", 2, k, v));
+}
+
+void
+StringType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, Variable**)
+{
+ addTo->Add(new Assignment(v, new MethodCall(data, "getString", 1, k)));
+}
+
// ================================================================
CharSequenceType::CharSequenceType()
- :Type("java.lang", "CharSequence", BUILT_IN, true, false)
+ :Type("java.lang", "CharSequence", BUILT_IN, true, true, false)
{
}
@@ -521,7 +637,7 @@
// ================================================================
RemoteExceptionType::RemoteExceptionType()
- :Type("android.os", "RemoteException", BUILT_IN, false, false)
+ :Type("android.os", "RemoteException", BUILT_IN, false, false, false)
{
}
@@ -540,7 +656,7 @@
// ================================================================
RuntimeExceptionType::RuntimeExceptionType()
- :Type("java.lang", "RuntimeException", BUILT_IN, false, false)
+ :Type("java.lang", "RuntimeException", BUILT_IN, false, false, false)
{
}
@@ -560,7 +676,7 @@
// ================================================================
IBinderType::IBinderType()
- :Type("android.os", "IBinder", BUILT_IN, true, false)
+ :Type("android.os", "IBinder", BUILT_IN, true, false, false)
{
}
@@ -599,7 +715,7 @@
// ================================================================
IInterfaceType::IInterfaceType()
- :Type("android.os", "IInterface", BUILT_IN, false, false)
+ :Type("android.os", "IInterface", BUILT_IN, false, false, false)
{
}
@@ -619,7 +735,7 @@
// ================================================================
BinderType::BinderType()
- :Type("android.os", "Binder", BUILT_IN, false, false)
+ :Type("android.os", "Binder", BUILT_IN, false, false, false)
{
}
@@ -640,7 +756,7 @@
// ================================================================
BinderProxyType::BinderProxyType()
- :Type("android.os", "BinderProxy", BUILT_IN, false, false)
+ :Type("android.os", "BinderProxy", BUILT_IN, false, false, false)
{
}
@@ -661,7 +777,7 @@
// ================================================================
ParcelType::ParcelType()
- :Type("android.os", "Parcel", BUILT_IN, false, false)
+ :Type("android.os", "Parcel", BUILT_IN, false, false, false)
{
}
@@ -680,7 +796,7 @@
// ================================================================
ParcelableInterfaceType::ParcelableInterfaceType()
- :Type("android.os", "Parcelable", BUILT_IN, false, false)
+ :Type("android.os", "Parcelable", BUILT_IN, false, false, false)
{
}
@@ -699,7 +815,7 @@
// ================================================================
MapType::MapType()
- :Type("java.util", "Map", BUILT_IN, true, true)
+ :Type("java.util", "Map", BUILT_IN, true, false, true)
{
}
@@ -729,8 +845,7 @@
}
void
-MapType::ReadFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl)
+MapType::ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl)
{
EnsureClassLoader(addTo, cl);
addTo->Add(new MethodCall(parcel, "readMap", 2, v, *cl));
@@ -740,7 +855,7 @@
// ================================================================
ListType::ListType()
- :Type("java.util", "List", BUILT_IN, true, true)
+ :Type("java.util", "List", BUILT_IN, true, true, true)
{
}
@@ -771,24 +886,44 @@
addTo->Add(new MethodCall(parcel, "readList", 2, v, *cl));
}
+void
+ListType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags)
+{
+ addTo->Add(new MethodCall(data, "putList", 2, k, v));
+}
+
+void
+ListType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
+ Variable** cl)
+{
+ addTo->Add(new Assignment(v, new MethodCall(data, "getList", 1, k)));
+}
// ================================================================
-ParcelableType::ParcelableType(const string& package, const string& name,
- bool builtIn, const string& declFile, int declLine)
- :Type(package, name, builtIn ? BUILT_IN : PARCELABLE, true, true,
- declFile, declLine)
+UserDataType::UserDataType(const string& package, const string& name,
+ bool builtIn, bool canWriteToParcel, bool canWriteToRpcData,
+ const string& declFile, int declLine)
+ :Type(package, name, builtIn ? BUILT_IN : USERDATA, canWriteToParcel, canWriteToRpcData,
+ true, declFile, declLine)
{
}
string
-ParcelableType::CreatorName() const
+UserDataType::CreatorName() const
{
return QualifiedName() + ".CREATOR";
}
+string
+UserDataType::RpcCreatorName() const
+{
+ return QualifiedName() + ".RPC_CREATOR";
+}
+
void
-ParcelableType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+UserDataType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
{
// if (v != null) {
// parcel.writeInt(1);
@@ -811,7 +946,7 @@
}
void
-ParcelableType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
+UserDataType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
// if (0 != parcel.readInt()) {
// v = CLASS.CREATOR.createFromParcel(parcel)
@@ -832,7 +967,7 @@
}
void
-ParcelableType::ReadFromParcel(StatementBlock* addTo, Variable* v,
+UserDataType::ReadFromParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, Variable**)
{
// TODO: really, we don't need to have this extra check, but we
@@ -848,20 +983,20 @@
}
bool
-ParcelableType::CanBeArray() const
+UserDataType::CanBeArray() const
{
return true;
}
void
-ParcelableType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+UserDataType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
{
addTo->Add(new MethodCall(parcel, "writeTypedArray", 2, v,
BuildWriteToParcelFlags(flags)));
}
void
-ParcelableType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+UserDataType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, Variable**)
{
string creator = v->type->QualifiedName() + ".CREATOR";
@@ -870,20 +1005,36 @@
}
void
-ParcelableType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
+UserDataType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
string creator = v->type->QualifiedName() + ".CREATOR";
addTo->Add(new MethodCall(parcel, "readTypedArray", 2,
v, new LiteralExpression(creator)));
}
+void
+UserDataType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags)
+{
+ // data.putFlattenable(k, v);
+ addTo->Add(new MethodCall(data, "putFlattenable", 2, k, v));
+}
+
+void
+UserDataType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, Variable** cl)
+{
+ // data.getFlattenable(k, CLASS.RPC_CREATOR);
+ addTo->Add(new Assignment(v, new MethodCall(data, "getFlattenable", 2, k,
+ new FieldVariable(v->type, "RPC_CREATOR"))));
+}
// ================================================================
InterfaceType::InterfaceType(const string& package, const string& name,
bool builtIn, bool oneway,
const string& declFile, int declLine)
- :Type(package, name, builtIn ? BUILT_IN : INTERFACE, true, false,
+ :Type(package, name, builtIn ? BUILT_IN : INTERFACE, true, false, false,
declFile, declLine)
,m_oneway(oneway)
{
@@ -922,7 +1073,7 @@
GenericType::GenericType(const string& package, const string& name,
const vector<Type*>& args)
- :Type(package, name, BUILT_IN, true, true)
+ :Type(package, name, BUILT_IN, true, true, true)
{
m_args = args;
@@ -942,6 +1093,12 @@
SetQualifiedName(m_importName + gen);
}
+const vector<Type*>&
+GenericType::GenericArgumentTypes() const
+{
+ return m_args;
+}
+
string
GenericType::GenericArguments() const
{
@@ -1041,10 +1198,65 @@
}
}
+void
+GenericListType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags)
+{
+ Type* generic = GenericArgumentTypes()[0];
+ if (generic == RPC_DATA_TYPE) {
+ addTo->Add(new MethodCall(data, "putRpcDataList", 2, k, v));
+ } else if (generic->RpcCreatorName() != "") {
+ addTo->Add(new MethodCall(data, "putFlattenableList", 2, k, v));
+ } else {
+ addTo->Add(new MethodCall(data, "putList", 2, k, v));
+ }
+}
+
+void
+GenericListType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, Variable** cl)
+{
+ Type* generic = GenericArgumentTypes()[0];
+ if (generic == RPC_DATA_TYPE) {
+ addTo->Add(new Assignment(v, new MethodCall(data, "getRpcDataList", 2, k)));
+ } else if (generic->RpcCreatorName() != "") {
+ addTo->Add(new Assignment(v, new MethodCall(data, "getFlattenableList", 2, k,
+ new LiteralExpression(generic->RpcCreatorName()))));
+ } else {
+ string classArg = GenericArgumentTypes()[0]->QualifiedName();
+ classArg += ".class";
+ addTo->Add(new Assignment(v, new MethodCall(data, "getList", 2, k,
+ new LiteralExpression(classArg))));
+ }
+}
+
+
+// ================================================================
+
+RpcDataType::RpcDataType()
+ :UserDataType("com.android.athome.rpc", "RpcData", true, true, true)
+{
+}
+
+void
+RpcDataType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags)
+{
+ addTo->Add(new MethodCall(data, "putRpcData", 2, k, v));
+}
+
+void
+RpcDataType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
+ Variable** cl)
+{
+ addTo->Add(new Assignment(v, new MethodCall(data, "getRpcData", 1, k)));
+}
+
+
// ================================================================
ClassLoaderType::ClassLoaderType()
- :Type("java.lang", "ClassLoader", BUILT_IN, false, false)
+ :Type("java.lang", "ClassLoader", BUILT_IN, false, false, false)
{
}
diff --git a/tools/aidl/Type.h b/tools/aidl/Type.h
index 662e3a2..ae12720 100755
--- a/tools/aidl/Type.h
+++ b/tools/aidl/Type.h
@@ -13,7 +13,7 @@
// kinds
enum {
BUILT_IN,
- PARCELABLE,
+ USERDATA,
INTERFACE,
GENERATED
};
@@ -24,9 +24,9 @@
};
Type(const string& name, int kind, bool canWriteToParcel,
- bool canBeOut);
+ bool canWriteToRpcData, bool canBeOut);
Type(const string& package, const string& name,
- int kind, bool canWriteToParcel, bool canBeOut,
+ int kind, bool canWriteToParcel, bool canWriteToRpcData, bool canBeOut,
const string& declFile = "", int declLine = -1);
virtual ~Type();
@@ -36,11 +36,13 @@
inline int Kind() const { return m_kind; }
inline string DeclFile() const { return m_declFile; }
inline int DeclLine() const { return m_declLine; }
- inline bool CanBeMarshalled() const { return m_canWriteToParcel; }
+ inline bool CanWriteToParcel() const { return m_canWriteToParcel; }
+ inline bool CanWriteToRpcData() const { return m_canWriteToRpcData; }
inline bool CanBeOutParameter() const { return m_canBeOut; }
virtual string ImportType() const;
virtual string CreatorName() const;
+ virtual string RpcCreatorName() const;
virtual string InstantiableName() const;
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
@@ -59,6 +61,11 @@
virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, Variable** cl);
+ virtual void WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags);
+ virtual void CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, Variable** cl);
+
protected:
void SetQualifiedName(const string& qualified);
Expression* BuildWriteToParcelFlags(int flags);
@@ -74,17 +81,24 @@
int m_declLine;
int m_kind;
bool m_canWriteToParcel;
+ bool m_canWriteToRpcData;
bool m_canBeOut;
};
class BasicType : public Type
{
public:
- BasicType(const string& name, const string& marshallMethod,
- const string& unmarshallMethod,
- const string& writeArray,
- const string& createArray,
- const string& readArray);
+ BasicType(const string& name,
+ const string& marshallParcel,
+ const string& unmarshallParcel,
+ const string& writeArrayParcel,
+ const string& createArrayParcel,
+ const string& readArrayParcel,
+ const string& marshallRpc,
+ const string& unmarshallRpc,
+ const string& writeArrayRpc,
+ const string& createArrayRpc,
+ const string& readArrayRpc);
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
@@ -100,12 +114,22 @@
virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, Variable** cl);
+ virtual void WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags);
+ virtual void CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, Variable** cl);
+
private:
- string m_marshallMethod;
- string m_unmarshallMethod;
- string m_writeArrayMethod;
- string m_createArrayMethod;
- string m_readArrayMethod;
+ string m_marshallParcel;
+ string m_unmarshallParcel;
+ string m_writeArrayParcel;
+ string m_createArrayParcel;
+ string m_readArrayParcel;
+ string m_marshallRpc;
+ string m_unmarshallRpc;
+ string m_writeArrayRpc;
+ string m_createArrayRpc;
+ string m_readArrayRpc;
};
class BooleanType : public Type
@@ -126,6 +150,11 @@
Variable* parcel, Variable** cl);
virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, Variable** cl);
+
+ virtual void WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags);
+ virtual void CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, Variable** cl);
};
class CharType : public Type
@@ -146,6 +175,11 @@
Variable* parcel, Variable** cl);
virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, Variable** cl);
+
+ virtual void WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags);
+ virtual void CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, Variable** cl);
};
@@ -169,6 +203,11 @@
Variable* parcel, Variable** cl);
virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, Variable** cl);
+
+ virtual void WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags);
+ virtual void CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, Variable** cl);
};
class CharSequenceType : public Type
@@ -305,15 +344,22 @@
Variable* parcel, Variable** cl);
virtual void ReadFromParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, Variable** cl);
+
+ virtual void WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags);
+ virtual void CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, Variable** cl);
};
-class ParcelableType : public Type
+class UserDataType : public Type
{
public:
- ParcelableType(const string& package, const string& name,
- bool builtIn, const string& declFile, int declLine);
+ UserDataType(const string& package, const string& name,
+ bool builtIn, bool canWriteToParcel, bool canWriteToRpcData,
+ const string& declFile = "", int declLine = -1);
virtual string CreatorName() const;
+ virtual string RpcCreatorName() const;
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
@@ -330,6 +376,11 @@
Variable* parcel, Variable** cl);
virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, Variable** cl);
+
+ virtual void WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags);
+ virtual void CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, Variable** cl);
};
class InterfaceType : public Type
@@ -357,6 +408,7 @@
GenericType(const string& package, const string& name,
const vector<Type*>& args);
+ const vector<Type*>& GenericArgumentTypes() const;
string GenericArguments() const;
virtual string ImportType() const;
@@ -374,6 +426,22 @@
vector<Type*> m_args;
};
+class RpcDataType : public UserDataType
+{
+public:
+ RpcDataType();
+
+ virtual void WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags);
+ virtual void CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, Variable** cl);
+};
+
+class ClassLoaderType : public Type
+{
+public:
+ ClassLoaderType();
+};
class GenericListType : public GenericType
{
@@ -391,16 +459,15 @@
virtual void ReadFromParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, Variable** cl);
+ virtual void WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags);
+ virtual void CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, Variable** cl);
+
private:
string m_creator;
};
-class ClassLoaderType : public Type
-{
-public:
- ClassLoaderType();
-};
-
class Namespace
{
public:
@@ -438,11 +505,13 @@
extern Type* VOID_TYPE;
extern Type* BOOLEAN_TYPE;
+extern Type* BYTE_TYPE;
extern Type* CHAR_TYPE;
extern Type* INT_TYPE;
extern Type* LONG_TYPE;
extern Type* FLOAT_TYPE;
extern Type* DOUBLE_TYPE;
+extern Type* OBJECT_TYPE;
extern Type* STRING_TYPE;
extern Type* CHAR_SEQUENCE_TYPE;
extern Type* TEXT_UTILS_TYPE;
@@ -455,6 +524,13 @@
extern Type* PARCEL_TYPE;
extern Type* PARCELABLE_INTERFACE_TYPE;
+extern Type* CONTEXT_TYPE;
+
+extern Type* RPC_DATA_TYPE;
+extern Type* RPC_ERROR_TYPE;
+extern Type* RPC_CONTEXT_TYPE;
+extern Type* EVENT_FAKE_TYPE;
+
extern Expression* NULL_VALUE;
extern Expression* THIS_VALUE;
extern Expression* SUPER_VALUE;
diff --git a/tools/aidl/aidl.cpp b/tools/aidl/aidl.cpp
index fb4067a..8dbbf50 100644
--- a/tools/aidl/aidl.cpp
+++ b/tools/aidl/aidl.cpp
@@ -29,7 +29,7 @@
test_document(document_item_type* d)
{
while (d) {
- if (d->item_type == INTERFACE_TYPE) {
+ if (d->item_type == INTERFACE_TYPE_BINDER) {
interface_type* c = (interface_type*)d;
printf("interface %s %s {\n", c->package, c->name.data);
interface_item_type *q = (interface_item_type*)c->interface_items;
@@ -50,9 +50,14 @@
}
printf("}\n");
}
- else if (d->item_type == PARCELABLE_TYPE) {
- parcelable_type* b = (parcelable_type*)d;
- printf("parcelable %s %s;\n", b->package, b->name.data);
+ else if (d->item_type == USER_DATA_TYPE) {
+ user_data_type* b = (user_data_type*)d;
+ if ((b->flattening_methods & PARCELABLE_DATA) != 0) {
+ printf("parcelable %s %s;\n", b->package, b->name.data);
+ }
+ if ((b->flattening_methods & RPC_DATA) != 0) {
+ printf("flattenable %s %s;\n", b->package, b->name.data);
+ }
}
else {
printf("UNKNOWN d=0x%08lx d->item_type=%d\n", (long)d, d->item_type);
@@ -238,11 +243,12 @@
{
int err = 0;
while (items) {
- if (items->item_type == PARCELABLE_TYPE) {
- parcelable_type* p = (parcelable_type*)items;
+ if (items->item_type == USER_DATA_TYPE) {
+ user_data_type* p = (user_data_type*)items;
err |= check_filename(filename, p->package, &p->name);
}
- else if (items->item_type == INTERFACE_TYPE) {
+ else if (items->item_type == INTERFACE_TYPE_BINDER
+ || items->item_type == INTERFACE_TYPE_RPC) {
interface_type* c = (interface_type*)items;
err |= check_filename(filename, c->package, &c->name);
}
@@ -264,8 +270,8 @@
{
case Type::INTERFACE:
return "an interface";
- case Type::PARCELABLE:
- return "a parcelable";
+ case Type::USERDATA:
+ return "a user data";
default:
return "ERROR";
}
@@ -290,12 +296,14 @@
int err = 0;
while (items) {
Type* type;
- if (items->item_type == PARCELABLE_TYPE) {
- parcelable_type* p = (parcelable_type*)items;
- type = new ParcelableType(p->package ? p->package : "",
- p->name.data, false, filename, p->name.lineno);
+ if (items->item_type == USER_DATA_TYPE) {
+ user_data_type* p = (user_data_type*)items;
+ type = new UserDataType(p->package ? p->package : "", p->name.data,
+ false, ((p->flattening_methods & PARCELABLE_DATA) != 0),
+ ((p->flattening_methods & RPC_DATA) != 0), filename, p->name.lineno);
}
- else if (items->item_type == INTERFACE_TYPE) {
+ else if (items->item_type == INTERFACE_TYPE_BINDER
+ || items->item_type == INTERFACE_TYPE_RPC) {
interface_type* c = (interface_type*)items;
type = new InterfaceType(c->package ? c->package : "",
c->name.data, false, c->oneway,
@@ -310,7 +318,7 @@
if (old == NULL) {
NAMES.Add(type);
- if (items->item_type == INTERFACE_TYPE) {
+ if (items->item_type == INTERFACE_TYPE_BINDER) {
// for interfaces, also add the stub and proxy types, we don't
// bother checking these for duplicates, because the parser
// won't let us do it.
@@ -319,17 +327,30 @@
string name = c->name.data;
name += ".Stub";
Type* stub = new Type(c->package ? c->package : "",
- name, Type::GENERATED, false, false,
+ name, Type::GENERATED, false, false, false,
filename, c->name.lineno);
NAMES.Add(stub);
name = c->name.data;
name += ".Stub.Proxy";
Type* proxy = new Type(c->package ? c->package : "",
- name, Type::GENERATED, false, false,
+ name, Type::GENERATED, false, false, false,
filename, c->name.lineno);
NAMES.Add(proxy);
}
+ else if (items->item_type == INTERFACE_TYPE_RPC) {
+ // for interfaces, also add the service base type, we don't
+ // bother checking these for duplicates, because the parser
+ // won't let us do it.
+ interface_type* c = (interface_type*)items;
+
+ string name = c->name.data;
+ name += ".ServiceBase";
+ Type* base = new Type(c->package ? c->package : "",
+ name, Type::GENERATED, false, false, false,
+ filename, c->name.lineno);
+ NAMES.Add(base);
+ }
} else {
if (old->Kind() == Type::BUILT_IN) {
fprintf(stderr, "%s:%d attempt to redefine built in class %s\n",
@@ -381,7 +402,7 @@
}
static int
-check_method(const char* filename, method_type* m)
+check_method(const char* filename, int kind, method_type* m)
{
int err = 0;
@@ -394,10 +415,19 @@
return err;
}
- if (!returnType->CanBeMarshalled()) {
- fprintf(stderr, "%s:%d return type %s can't be marshalled.\n", filename,
- m->type.type.lineno, m->type.type.data);
- err = 1;
+ if (returnType == EVENT_FAKE_TYPE) {
+ if (kind != INTERFACE_TYPE_RPC) {
+ fprintf(stderr, "%s:%d event methods only supported for rpc interfaces\n",
+ filename, m->type.type.lineno);
+ err = 1;
+ }
+ } else {
+ if (!(kind == INTERFACE_TYPE_BINDER ? returnType->CanWriteToParcel()
+ : returnType->CanWriteToRpcData())) {
+ fprintf(stderr, "%s:%d return type %s can't be marshalled.\n", filename,
+ m->type.type.lineno, m->type.type.data);
+ err = 1;
+ }
}
if (m->type.dimension > 0 && !returnType->CanBeArray()) {
@@ -429,14 +459,31 @@
err = 1;
goto next;
}
+
+ if (t == EVENT_FAKE_TYPE) {
+ fprintf(stderr, "%s:%d parameter %s (%d) event can not be used as a parameter %s\n",
+ filename, m->type.type.lineno, arg->name.data, index,
+ arg->type.type.data);
+ err = 1;
+ goto next;
+ }
- if (!t->CanBeMarshalled()) {
+ if (!(kind == INTERFACE_TYPE_BINDER ? t->CanWriteToParcel() : t->CanWriteToRpcData())) {
fprintf(stderr, "%s:%d parameter %d: '%s %s' can't be marshalled.\n",
filename, m->type.type.lineno, index,
arg->type.type.data, arg->name.data);
err = 1;
}
+ if (returnType == EVENT_FAKE_TYPE
+ && convert_direction(arg->direction.data) != IN_PARAMETER) {
+ fprintf(stderr, "%s:%d parameter %d: '%s %s' All paremeters on events must be 'in'.\n",
+ filename, m->type.type.lineno, index,
+ arg->type.type.data, arg->name.data);
+ err = 1;
+ goto next;
+ }
+
if (arg->direction.data == NULL
&& (arg->type.dimension != 0 || t->CanBeOutParameter())) {
fprintf(stderr, "%s:%d parameter %d: '%s %s' can be an out"
@@ -479,7 +526,7 @@
// check that the name doesn't match a keyword
if (matches_keyword(arg->name.data)) {
fprintf(stderr, "%s:%d parameter %d %s is named the same as a"
- " Java keyword\n",
+ " Java or aidl keyword\n",
filename, m->name.lineno, index, arg->name.data);
err = 1;
}
@@ -497,8 +544,9 @@
{
int err = 0;
while (items) {
- // (nothing to check for PARCELABLE_TYPE)
- if (items->item_type == INTERFACE_TYPE) {
+ // (nothing to check for USER_DATA_TYPE)
+ if (items->item_type == INTERFACE_TYPE_BINDER
+ || items->item_type == INTERFACE_TYPE_RPC) {
map<string,method_type*> methodNames;
interface_type* c = (interface_type*)items;
@@ -507,7 +555,7 @@
if (member->item_type == METHOD_TYPE) {
method_type* m = (method_type*)member;
- err |= check_method(filename, m);
+ err |= check_method(filename, items->item_type, m);
// prevent duplicate methods
if (methodNames.find(m->name.data) == methodNames.end()) {
@@ -544,26 +592,29 @@
const document_item_type* next = items->next;
if (items->next != NULL) {
int lineno = -1;
- if (next->item_type == INTERFACE_TYPE) {
+ if (next->item_type == INTERFACE_TYPE_BINDER) {
lineno = ((interface_type*)next)->interface_token.lineno;
}
- else if (next->item_type == PARCELABLE_TYPE) {
- lineno = ((parcelable_type*)next)->parcelable_token.lineno;
+ else if (next->item_type == INTERFACE_TYPE_RPC) {
+ lineno = ((interface_type*)next)->interface_token.lineno;
+ }
+ else if (next->item_type == USER_DATA_TYPE) {
+ lineno = ((user_data_type*)next)->keyword_token.lineno;
}
fprintf(stderr, "%s:%d aidl can only handle one interface per file\n",
filename, lineno);
return 1;
}
- if (items->item_type == PARCELABLE_TYPE) {
+ if (items->item_type == USER_DATA_TYPE) {
*onlyParcelable = true;
if (options.failOnParcelable) {
fprintf(stderr, "%s:%d aidl can only generate code for interfaces, not"
- " parcelables,\n", filename,
- ((parcelable_type*)items)->parcelable_token.lineno);
- fprintf(stderr, "%s:%d .aidl files that only declare parcelables "
- "don't need to go in the Makefile.\n", filename,
- ((parcelable_type*)items)->parcelable_token.lineno);
+ " parcelables or flattenables,\n", filename,
+ ((user_data_type*)items)->keyword_token.lineno);
+ fprintf(stderr, "%s:%d .aidl files that only declare parcelables or flattenables"
+ "may not go in the Makefile.\n", filename,
+ ((user_data_type*)items)->keyword_token.lineno);
return 1;
}
} else {
@@ -598,7 +649,7 @@
slash = "";
}
- if (items->item_type == INTERFACE_TYPE) {
+ if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
fprintf(to, "%s: \\\n", options.outputFileName.c_str());
} else {
// parcelable: there's no output file.
@@ -658,12 +709,12 @@
generate_outputFileName(const Options& options, const document_item_type* items)
{
// items has already been checked to have only one interface.
- if (items->item_type == INTERFACE_TYPE) {
+ if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
interface_type* type = (interface_type*)items;
return generate_outputFileName2(options, type->name, type->package);
- } else if (items->item_type == PARCELABLE_TYPE) {
- parcelable_type* type = (parcelable_type*)items;
+ } else if (items->item_type == USER_DATA_TYPE) {
+ user_data_type* type = (user_data_type*)items;
return generate_outputFileName2(options, type->name, type->package);
}
@@ -734,24 +785,40 @@
document_item_type* doc;
if (0 == strcmp("parcelable", type)) {
- parcelable_type* parcl = (parcelable_type*)malloc(
- sizeof(parcelable_type));
- memset(parcl, 0, sizeof(parcelable_type));
- parcl->document_item.item_type = PARCELABLE_TYPE;
- parcl->parcelable_token.lineno = lineno;
- parcl->parcelable_token.data = strdup(type);
+ user_data_type* parcl = (user_data_type*)malloc(
+ sizeof(user_data_type));
+ memset(parcl, 0, sizeof(user_data_type));
+ parcl->document_item.item_type = USER_DATA_TYPE;
+ parcl->keyword_token.lineno = lineno;
+ parcl->keyword_token.data = strdup(type);
parcl->package = packagename ? strdup(packagename) : NULL;
parcl->name.lineno = lineno;
parcl->name.data = strdup(classname);
parcl->semicolon_token.lineno = lineno;
parcl->semicolon_token.data = strdup(";");
+ parcl->flattening_methods = PARCELABLE_DATA;
+ doc = (document_item_type*)parcl;
+ }
+ else if (0 == strcmp("flattenable", type)) {
+ user_data_type* parcl = (user_data_type*)malloc(
+ sizeof(user_data_type));
+ memset(parcl, 0, sizeof(user_data_type));
+ parcl->document_item.item_type = USER_DATA_TYPE;
+ parcl->keyword_token.lineno = lineno;
+ parcl->keyword_token.data = strdup(type);
+ parcl->package = packagename ? strdup(packagename) : NULL;
+ parcl->name.lineno = lineno;
+ parcl->name.data = strdup(classname);
+ parcl->semicolon_token.lineno = lineno;
+ parcl->semicolon_token.data = strdup(";");
+ parcl->flattening_methods = RPC_DATA;
doc = (document_item_type*)parcl;
}
else if (0 == strcmp("interface", type)) {
interface_type* iface = (interface_type*)malloc(
sizeof(interface_type));
memset(iface, 0, sizeof(interface_type));
- iface->document_item.item_type = INTERFACE_TYPE;
+ iface->document_item.item_type = INTERFACE_TYPE_BINDER;
iface->interface_token.lineno = lineno;
iface->interface_token.data = strdup(type);
iface->package = packagename ? strdup(packagename) : NULL;
@@ -923,9 +990,14 @@
}
document_item_type* doc = g_document;
string line;
- if (doc->item_type == PARCELABLE_TYPE) {
- line = "parcelable ";
- parcelable_type* parcelable = (parcelable_type*)doc;
+ if (doc->item_type == USER_DATA_TYPE) {
+ user_data_type* parcelable = (user_data_type*)doc;
+ if ((parcelable->flattening_methods & PARCELABLE_DATA) != 0) {
+ line = "parcelable ";
+ }
+ if ((parcelable->flattening_methods & RPC_DATA) != 0) {
+ line = "flattenable ";
+ }
if (parcelable->package) {
line += parcelable->package;
line += '.';
@@ -995,5 +1067,3 @@
fprintf(stderr, "aidl: internal error\n");
return 1;
}
-
-
diff --git a/tools/aidl/aidl_language.h b/tools/aidl/aidl_language.h
index 9ca5deb..f203dbb0 100644
--- a/tools/aidl/aidl_language.h
+++ b/tools/aidl/aidl_language.h
@@ -63,8 +63,9 @@
} method_type;
enum {
- PARCELABLE_TYPE = 12,
- INTERFACE_TYPE
+ USER_DATA_TYPE = 12,
+ INTERFACE_TYPE_BINDER,
+ INTERFACE_TYPE_RPC
};
typedef struct document_item_type {
@@ -72,13 +73,21 @@
struct document_item_type* next;
} document_item_type;
-typedef struct parcelable_type {
+
+// for user_data_type.flattening_methods
+enum {
+ PARCELABLE_DATA = 0x1,
+ RPC_DATA = 0x2
+};
+
+typedef struct user_data_type {
document_item_type document_item;
- buffer_type parcelable_token;
+ buffer_type keyword_token; // only the first one
char* package;
buffer_type name;
buffer_type semicolon_token;
-} parcelable_type;
+ int flattening_methods;
+} user_data_type;
typedef struct interface_type {
document_item_type document_item;
@@ -100,7 +109,7 @@
method_type* method;
interface_item_type* interface_item;
interface_type* interface_obj;
- parcelable_type* parcelable;
+ user_data_type* user_data;
document_item_type* document_item;
} lexer_type;
diff --git a/tools/aidl/aidl_language_l.l b/tools/aidl/aidl_language_l.l
index 567b1cf..7c5290c 100644
--- a/tools/aidl/aidl_language_l.l
+++ b/tools/aidl/aidl_language_l.l
@@ -81,6 +81,8 @@
/* keywords */
parcelable { SET_BUFFER(PARCELABLE); return PARCELABLE; }
interface { SET_BUFFER(INTERFACE); return INTERFACE; }
+flattenable { SET_BUFFER(FLATTENABLE); return FLATTENABLE; }
+rpc { SET_BUFFER(INTERFACE); return RPC; }
in { SET_BUFFER(IN); return IN; }
out { SET_BUFFER(OUT); return OUT; }
inout { SET_BUFFER(INOUT); return INOUT; }
diff --git a/tools/aidl/aidl_language_y.y b/tools/aidl/aidl_language_y.y
index 3d65f17..cc04d15 100644
--- a/tools/aidl/aidl_language_y.y
+++ b/tools/aidl/aidl_language_y.y
@@ -19,6 +19,8 @@
%token ARRAY
%token PARCELABLE
%token INTERFACE
+%token FLATTENABLE
+%token RPC
%token IN
%token OUT
%token INOUT
@@ -72,36 +74,61 @@
;
declaration:
- parcelable_decl { $$.document_item = (document_item_type*)$1.parcelable; }
+ parcelable_decl { $$.document_item = (document_item_type*)$1.user_data; }
| interface_decl { $$.document_item = (document_item_type*)$1.interface_item; }
;
parcelable_decl:
- PARCELABLE IDENTIFIER ';' {
- parcelable_type* b = (parcelable_type*)malloc(sizeof(parcelable_type));
- b->document_item.item_type = PARCELABLE_TYPE;
+ PARCELABLE IDENTIFIER ';' {
+ user_data_type* b = (user_data_type*)malloc(sizeof(user_data_type));
+ b->document_item.item_type = USER_DATA_TYPE;
b->document_item.next = NULL;
- b->parcelable_token = $1.buffer;
+ b->keyword_token = $1.buffer;
b->name = $2.buffer;
b->package = g_currentPackage ? strdup(g_currentPackage) : NULL;
b->semicolon_token = $3.buffer;
- $$.parcelable = b;
+ b->flattening_methods = PARCELABLE_DATA;
+ $$.user_data = b;
}
| PARCELABLE ';' {
fprintf(stderr, "%s:%d syntax error in parcelable declaration. Expected type name.\n",
g_currentFilename, $1.buffer.lineno);
- $$.parcelable = NULL;
+ $$.user_data = NULL;
}
| PARCELABLE error ';' {
fprintf(stderr, "%s:%d syntax error in parcelable declaration. Expected type name, saw \"%s\".\n",
g_currentFilename, $2.buffer.lineno, $2.buffer.data);
- $$.parcelable = NULL;
+ $$.user_data = NULL;
}
+ | FLATTENABLE IDENTIFIER ';' {
+ user_data_type* b = (user_data_type*)malloc(sizeof(user_data_type));
+ b->document_item.item_type = USER_DATA_TYPE;
+ b->document_item.next = NULL;
+ b->keyword_token = $1.buffer;
+ b->name = $2.buffer;
+ b->package = g_currentPackage ? strdup(g_currentPackage) : NULL;
+ b->semicolon_token = $3.buffer;
+ b->flattening_methods = PARCELABLE_DATA | RPC_DATA;
+ $$.user_data = b;
+ }
+ | FLATTENABLE ';' {
+ fprintf(stderr, "%s:%d syntax error in flattenable declaration. Expected type name.\n",
+ g_currentFilename, $1.buffer.lineno);
+ $$.user_data = NULL;
+ }
+ | FLATTENABLE error ';' {
+ fprintf(stderr, "%s:%d syntax error in flattenable declaration. Expected type name, saw \"%s\".\n",
+ g_currentFilename, $2.buffer.lineno, $2.buffer.data);
+ $$.user_data = NULL;
+ }
+
;
interface_header:
INTERFACE {
interface_type* c = (interface_type*)malloc(sizeof(interface_type));
+ c->document_item.item_type = INTERFACE_TYPE_BINDER;
+ c->document_item.next = NULL;
c->interface_token = $1.buffer;
c->oneway = false;
memset(&c->oneway_token, 0, sizeof(buffer_type));
@@ -110,19 +137,34 @@
}
| ONEWAY INTERFACE {
interface_type* c = (interface_type*)malloc(sizeof(interface_type));
+ c->document_item.item_type = INTERFACE_TYPE_BINDER;
+ c->document_item.next = NULL;
c->interface_token = $2.buffer;
c->oneway = true;
c->oneway_token = $1.buffer;
c->comments_token = &c->oneway_token;
$$.interface_obj = c;
}
+ | RPC {
+ interface_type* c = (interface_type*)malloc(sizeof(interface_type));
+ c->document_item.item_type = INTERFACE_TYPE_RPC;
+ c->document_item.next = NULL;
+ c->interface_token = $1.buffer;
+ c->oneway = false;
+ memset(&c->oneway_token, 0, sizeof(buffer_type));
+ c->comments_token = &c->interface_token;
+ $$.interface_obj = c;
+ }
+ ;
+
+interface_keywords:
+ INTERFACE
+ | RPC
;
interface_decl:
interface_header IDENTIFIER '{' interface_items '}' {
interface_type* c = $1.interface_obj;
- c->document_item.item_type = INTERFACE_TYPE;
- c->document_item.next = NULL;
c->name = $2.buffer;
c->package = g_currentPackage ? strdup(g_currentPackage) : NULL;
c->open_brace_token = $3.buffer;
@@ -130,12 +172,12 @@
c->close_brace_token = $5.buffer;
$$.interface_obj = c;
}
- | INTERFACE error '{' interface_items '}' {
+ | interface_keywords error '{' interface_items '}' {
fprintf(stderr, "%s:%d: syntax error in interface declaration. Expected type name, saw \"%s\"\n",
g_currentFilename, $2.buffer.lineno, $2.buffer.data);
$$.document_item = NULL;
}
- | INTERFACE error '}' {
+ | interface_keywords error '}' {
fprintf(stderr, "%s:%d: syntax error in interface declaration. Expected type name, saw \"%s\"\n",
g_currentFilename, $2.buffer.lineno, $2.buffer.data);
$$.document_item = NULL;
diff --git a/tools/aidl/generate_java.cpp b/tools/aidl/generate_java.cpp
index 83e3bbc..9e57407 100644
--- a/tools/aidl/generate_java.cpp
+++ b/tools/aidl/generate_java.cpp
@@ -1,5 +1,4 @@
#include "generate_java.h"
-#include "AST.h"
#include "Type.h"
#include <string.h>
#include <stdio.h>
@@ -7,18 +6,6 @@
#include <string.h>
// =================================================
-class VariableFactory
-{
-public:
- VariableFactory(const string& base); // base must be short
- Variable* Get(Type* type);
- Variable* Get(int index);
-private:
- vector<Variable*> m_vars;
- string m_base;
- int m_index;
-};
-
VariableFactory::VariableFactory(const string& base)
:m_base(base),
m_index(0)
@@ -43,195 +30,7 @@
}
// =================================================
-class StubClass : public Class
-{
-public:
- StubClass(Type* type, Type* interfaceType);
- virtual ~StubClass();
-
- Variable* transact_code;
- Variable* transact_data;
- Variable* transact_reply;
- Variable* transact_flags;
- SwitchStatement* transact_switch;
-private:
- void make_as_interface(Type* interfaceType);
-};
-
-StubClass::StubClass(Type* type, Type* interfaceType)
- :Class()
-{
- this->comment = "/** Local-side IPC implementation stub class. */";
- this->modifiers = PUBLIC | ABSTRACT | STATIC;
- this->what = Class::CLASS;
- this->type = type;
- this->extends = BINDER_NATIVE_TYPE;
- this->interfaces.push_back(interfaceType);
-
- // descriptor
- Field* descriptor = new Field(STATIC | FINAL | PRIVATE,
- new Variable(STRING_TYPE, "DESCRIPTOR"));
- descriptor->value = "\"" + interfaceType->QualifiedName() + "\"";
- this->elements.push_back(descriptor);
-
- // ctor
- Method* ctor = new Method;
- ctor->modifiers = PUBLIC;
- ctor->comment = "/** Construct the stub at attach it to the "
- "interface. */";
- ctor->name = "Stub";
- ctor->statements = new StatementBlock;
- MethodCall* attach = new MethodCall(THIS_VALUE, "attachInterface",
- 2, THIS_VALUE, new LiteralExpression("DESCRIPTOR"));
- ctor->statements->Add(attach);
- this->elements.push_back(ctor);
-
- // asInterface
- make_as_interface(interfaceType);
-
- // asBinder
- Method* asBinder = new Method;
- asBinder->modifiers = PUBLIC;
- asBinder->returnType = IBINDER_TYPE;
- asBinder->name = "asBinder";
- asBinder->statements = new StatementBlock;
- asBinder->statements->Add(new ReturnStatement(THIS_VALUE));
- this->elements.push_back(asBinder);
-
- // onTransact
- this->transact_code = new Variable(INT_TYPE, "code");
- this->transact_data = new Variable(PARCEL_TYPE, "data");
- this->transact_reply = new Variable(PARCEL_TYPE, "reply");
- this->transact_flags = new Variable(INT_TYPE, "flags");
- Method* onTransact = new Method;
- onTransact->modifiers = PUBLIC | OVERRIDE;
- onTransact->returnType = BOOLEAN_TYPE;
- onTransact->name = "onTransact";
- onTransact->parameters.push_back(this->transact_code);
- onTransact->parameters.push_back(this->transact_data);
- onTransact->parameters.push_back(this->transact_reply);
- onTransact->parameters.push_back(this->transact_flags);
- onTransact->statements = new StatementBlock;
- onTransact->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
- this->elements.push_back(onTransact);
- this->transact_switch = new SwitchStatement(this->transact_code);
-
- onTransact->statements->Add(this->transact_switch);
- MethodCall* superCall = new MethodCall(SUPER_VALUE, "onTransact", 4,
- this->transact_code, this->transact_data,
- this->transact_reply, this->transact_flags);
- onTransact->statements->Add(new ReturnStatement(superCall));
-}
-
-StubClass::~StubClass()
-{
-}
-
-void
-StubClass::make_as_interface(Type *interfaceType)
-{
- Variable* obj = new Variable(IBINDER_TYPE, "obj");
-
- Method* m = new Method;
- m->comment = "/**\n * Cast an IBinder object into an ";
- m->comment += interfaceType->QualifiedName();
- m->comment += " interface,\n";
- m->comment += " * generating a proxy if needed.\n */";
- m->modifiers = PUBLIC | STATIC;
- m->returnType = interfaceType;
- m->name = "asInterface";
- m->parameters.push_back(obj);
- m->statements = new StatementBlock;
-
- IfStatement* ifstatement = new IfStatement();
- ifstatement->expression = new Comparison(obj, "==", NULL_VALUE);
- ifstatement->statements = new StatementBlock;
- ifstatement->statements->Add(new ReturnStatement(NULL_VALUE));
- m->statements->Add(ifstatement);
-
- // IInterface iin = obj.queryLocalInterface(DESCRIPTOR)
- MethodCall* queryLocalInterface = new MethodCall(obj, "queryLocalInterface");
- queryLocalInterface->arguments.push_back(new LiteralExpression("DESCRIPTOR"));
- IInterfaceType* iinType = new IInterfaceType();
- Variable *iin = new Variable(iinType, "iin");
- VariableDeclaration* iinVd = new VariableDeclaration(iin, queryLocalInterface, iinType);
- m->statements->Add(iinVd);
-
- // Ensure the instance type of the local object is as expected.
- // One scenario where this is needed is if another package (with a
- // different class loader) runs in the same process as the service.
-
- // if (iin != null && iin instanceof <interfaceType>) return (<interfaceType>) iin;
- Comparison* iinNotNull = new Comparison(iin, "!=", NULL_VALUE);
- Comparison* instOfCheck = new Comparison(iin, " instanceof ",
- new LiteralExpression(interfaceType->QualifiedName()));
- IfStatement* instOfStatement = new IfStatement();
- instOfStatement->expression = new Comparison(iinNotNull, "&&", instOfCheck);
- instOfStatement->statements = new StatementBlock;
- instOfStatement->statements->Add(new ReturnStatement(new Cast(interfaceType, iin)));
- m->statements->Add(instOfStatement);
-
- string proxyType = interfaceType->QualifiedName();
- proxyType += ".Stub.Proxy";
- NewExpression* ne = new NewExpression(NAMES.Find(proxyType));
- ne->arguments.push_back(obj);
- m->statements->Add(new ReturnStatement(ne));
-
- this->elements.push_back(m);
-}
-
-
-
-// =================================================
-class ProxyClass : public Class
-{
-public:
- ProxyClass(Type* type, InterfaceType* interfaceType);
- virtual ~ProxyClass();
-
- Variable* mRemote;
- bool mOneWay;
-};
-
-ProxyClass::ProxyClass(Type* type, InterfaceType* interfaceType)
- :Class()
-{
- this->modifiers = PRIVATE | STATIC;
- this->what = Class::CLASS;
- this->type = type;
- this->interfaces.push_back(interfaceType);
-
- mOneWay = interfaceType->OneWay();
-
- // IBinder mRemote
- mRemote = new Variable(IBINDER_TYPE, "mRemote");
- this->elements.push_back(new Field(PRIVATE, mRemote));
-
- // Proxy()
- Variable* remote = new Variable(IBINDER_TYPE, "remote");
- Method* ctor = new Method;
- ctor->name = "Proxy";
- ctor->statements = new StatementBlock;
- ctor->parameters.push_back(remote);
- ctor->statements->Add(new Assignment(mRemote, remote));
- this->elements.push_back(ctor);
-
- // IBinder asBinder()
- Method* asBinder = new Method;
- asBinder->modifiers = PUBLIC;
- asBinder->returnType = IBINDER_TYPE;
- asBinder->name = "asBinder";
- asBinder->statements = new StatementBlock;
- asBinder->statements->Add(new ReturnStatement(mRemote));
- this->elements.push_back(asBinder);
-}
-
-ProxyClass::~ProxyClass()
-{
-}
-
-// =================================================
-static string
+string
gather_comments(extra_text_type* extra)
{
string s;
@@ -249,7 +48,7 @@
return s;
}
-static string
+string
append(const char* a, const char* b)
{
string s = a;
@@ -257,379 +56,25 @@
return s;
}
-static void
-generate_new_array(Type* t, StatementBlock* addTo, Variable* v,
- Variable* parcel)
-{
- Variable* len = new Variable(INT_TYPE, v->name + "_length");
- addTo->Add(new VariableDeclaration(len, new MethodCall(parcel, "readInt")));
- IfStatement* lencheck = new IfStatement();
- lencheck->expression = new Comparison(len, "<", new LiteralExpression("0"));
- lencheck->statements->Add(new Assignment(v, NULL_VALUE));
- lencheck->elseif = new IfStatement();
- lencheck->elseif->statements->Add(new Assignment(v,
- new NewArrayExpression(t, len)));
- addTo->Add(lencheck);
-}
-
-static void
-generate_write_to_parcel(Type* t, StatementBlock* addTo, Variable* v,
- Variable* parcel, int flags)
-{
- if (v->dimension == 0) {
- t->WriteToParcel(addTo, v, parcel, flags);
- }
- if (v->dimension == 1) {
- t->WriteArrayToParcel(addTo, v, parcel, flags);
- }
-}
-
-static void
-generate_create_from_parcel(Type* t, StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl)
-{
- if (v->dimension == 0) {
- t->CreateFromParcel(addTo, v, parcel, cl);
- }
- if (v->dimension == 1) {
- t->CreateArrayFromParcel(addTo, v, parcel, cl);
- }
-}
-
-static void
-generate_read_from_parcel(Type* t, StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl)
-{
- if (v->dimension == 0) {
- t->ReadFromParcel(addTo, v, parcel, cl);
- }
- if (v->dimension == 1) {
- t->ReadArrayFromParcel(addTo, v, parcel, cl);
- }
-}
-
-
-static void
-generate_method(const method_type* method, Class* interface,
- StubClass* stubClass, ProxyClass* proxyClass, int index)
-{
- arg_type* arg;
- int i;
- bool hasOutParams = false;
-
- const bool oneway = proxyClass->mOneWay || method->oneway;
-
- // == the TRANSACT_ constant =============================================
- string transactCodeName = "TRANSACTION_";
- transactCodeName += method->name.data;
-
- char transactCodeValue[50];
- sprintf(transactCodeValue, "(android.os.IBinder.FIRST_CALL_TRANSACTION + %d)", index);
-
- Field* transactCode = new Field(STATIC | FINAL,
- new Variable(INT_TYPE, transactCodeName));
- transactCode->value = transactCodeValue;
- stubClass->elements.push_back(transactCode);
-
- // == the declaration in the interface ===================================
- Method* decl = new Method;
- decl->comment = gather_comments(method->comments_token->extra);
- decl->modifiers = PUBLIC;
- decl->returnType = NAMES.Search(method->type.type.data);
- decl->returnTypeDimension = method->type.dimension;
- decl->name = method->name.data;
-
- arg = method->args;
- while (arg != NULL) {
- decl->parameters.push_back(new Variable(
- NAMES.Search(arg->type.type.data), arg->name.data,
- arg->type.dimension));
- arg = arg->next;
- }
-
- decl->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
-
- interface->elements.push_back(decl);
-
- // == the stub method ====================================================
-
- Case* c = new Case(transactCodeName);
-
- MethodCall* realCall = new MethodCall(THIS_VALUE, method->name.data);
-
- // interface token validation is the very first thing we do
- c->statements->Add(new MethodCall(stubClass->transact_data,
- "enforceInterface", 1, new LiteralExpression("DESCRIPTOR")));
-
- // args
- Variable* cl = NULL;
- VariableFactory stubArgs("_arg");
- arg = method->args;
- while (arg != NULL) {
- Type* t = NAMES.Search(arg->type.type.data);
- Variable* v = stubArgs.Get(t);
- v->dimension = arg->type.dimension;
-
- c->statements->Add(new VariableDeclaration(v));
-
- if (convert_direction(arg->direction.data) & IN_PARAMETER) {
- generate_create_from_parcel(t, c->statements, v,
- stubClass->transact_data, &cl);
- } else {
- if (arg->type.dimension == 0) {
- c->statements->Add(new Assignment(
- v, new NewExpression(v->type)));
- }
- else if (arg->type.dimension == 1) {
- generate_new_array(v->type, c->statements, v,
- stubClass->transact_data);
- }
- else {
- fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__,
- __LINE__);
- }
- }
-
- realCall->arguments.push_back(v);
-
- arg = arg->next;
- }
-
- // the real call
- Variable* _result = NULL;
- if (0 == strcmp(method->type.type.data, "void")) {
- c->statements->Add(realCall);
-
- if (!oneway) {
- // report that there were no exceptions
- MethodCall* ex = new MethodCall(stubClass->transact_reply,
- "writeNoException", 0);
- c->statements->Add(ex);
- }
- } else {
- _result = new Variable(decl->returnType, "_result",
- decl->returnTypeDimension);
- c->statements->Add(new VariableDeclaration(_result, realCall));
-
- if (!oneway) {
- // report that there were no exceptions
- MethodCall* ex = new MethodCall(stubClass->transact_reply,
- "writeNoException", 0);
- c->statements->Add(ex);
- }
-
- // marshall the return value
- generate_write_to_parcel(decl->returnType, c->statements, _result,
- stubClass->transact_reply,
- Type::PARCELABLE_WRITE_RETURN_VALUE);
- }
-
- // out parameters
- i = 0;
- arg = method->args;
- while (arg != NULL) {
- Type* t = NAMES.Search(arg->type.type.data);
- Variable* v = stubArgs.Get(i++);
-
- if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
- generate_write_to_parcel(t, c->statements, v,
- stubClass->transact_reply,
- Type::PARCELABLE_WRITE_RETURN_VALUE);
- hasOutParams = true;
- }
-
- arg = arg->next;
- }
-
- // return true
- c->statements->Add(new ReturnStatement(TRUE_VALUE));
- stubClass->transact_switch->cases.push_back(c);
-
- // == the proxy method ===================================================
- Method* proxy = new Method;
- proxy->comment = gather_comments(method->comments_token->extra);
- proxy->modifiers = PUBLIC;
- proxy->returnType = NAMES.Search(method->type.type.data);
- proxy->returnTypeDimension = method->type.dimension;
- proxy->name = method->name.data;
- proxy->statements = new StatementBlock;
- arg = method->args;
- while (arg != NULL) {
- proxy->parameters.push_back(new Variable(
- NAMES.Search(arg->type.type.data), arg->name.data,
- arg->type.dimension));
- arg = arg->next;
- }
- proxy->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
- proxyClass->elements.push_back(proxy);
-
- // the parcels
- Variable* _data = new Variable(PARCEL_TYPE, "_data");
- proxy->statements->Add(new VariableDeclaration(_data,
- new MethodCall(PARCEL_TYPE, "obtain")));
- Variable* _reply = NULL;
- if (!oneway) {
- _reply = new Variable(PARCEL_TYPE, "_reply");
- proxy->statements->Add(new VariableDeclaration(_reply,
- new MethodCall(PARCEL_TYPE, "obtain")));
- }
-
- // the return value
- _result = NULL;
- if (0 != strcmp(method->type.type.data, "void")) {
- _result = new Variable(proxy->returnType, "_result",
- method->type.dimension);
- proxy->statements->Add(new VariableDeclaration(_result));
- }
-
- // try and finally
- TryStatement* tryStatement = new TryStatement();
- proxy->statements->Add(tryStatement);
- FinallyStatement* finallyStatement = new FinallyStatement();
- proxy->statements->Add(finallyStatement);
-
- // the interface identifier token: the DESCRIPTOR constant, marshalled as a string
- tryStatement->statements->Add(new MethodCall(_data, "writeInterfaceToken",
- 1, new LiteralExpression("DESCRIPTOR")));
-
- // the parameters
- arg = method->args;
- while (arg != NULL) {
- Type* t = NAMES.Search(arg->type.type.data);
- Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
- int dir = convert_direction(arg->direction.data);
- if (dir == OUT_PARAMETER && arg->type.dimension != 0) {
- IfStatement* checklen = new IfStatement();
- checklen->expression = new Comparison(v, "==", NULL_VALUE);
- checklen->statements->Add(new MethodCall(_data, "writeInt", 1,
- new LiteralExpression("-1")));
- checklen->elseif = new IfStatement();
- checklen->elseif->statements->Add(new MethodCall(_data, "writeInt",
- 1, new FieldVariable(v, "length")));
- tryStatement->statements->Add(checklen);
- }
- else if (dir & IN_PARAMETER) {
- generate_write_to_parcel(t, tryStatement->statements, v, _data, 0);
- }
- arg = arg->next;
- }
-
- // the transact call
- MethodCall* call = new MethodCall(proxyClass->mRemote, "transact", 4,
- new LiteralExpression("Stub." + transactCodeName),
- _data, _reply ? _reply : NULL_VALUE,
- new LiteralExpression(
- oneway ? "android.os.IBinder.FLAG_ONEWAY" : "0"));
- tryStatement->statements->Add(call);
-
- // throw back exceptions.
- if (_reply) {
- MethodCall* ex = new MethodCall(_reply, "readException", 0);
- tryStatement->statements->Add(ex);
- }
-
- // returning and cleanup
- if (_reply != NULL) {
- if (_result != NULL) {
- generate_create_from_parcel(proxy->returnType,
- tryStatement->statements, _result, _reply, &cl);
- }
-
- // the out/inout parameters
- arg = method->args;
- while (arg != NULL) {
- Type* t = NAMES.Search(arg->type.type.data);
- Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
- if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
- generate_read_from_parcel(t, tryStatement->statements,
- v, _reply, &cl);
- }
- arg = arg->next;
- }
-
- finallyStatement->statements->Add(new MethodCall(_reply, "recycle"));
- }
- finallyStatement->statements->Add(new MethodCall(_data, "recycle"));
-
- if (_result != NULL) {
- proxy->statements->Add(new ReturnStatement(_result));
- }
-}
-
-static void
-generate_interface_descriptors(StubClass* stub, ProxyClass* proxy)
-{
- // the interface descriptor transaction handler
- Case* c = new Case("INTERFACE_TRANSACTION");
- c->statements->Add(new MethodCall(stub->transact_reply, "writeString",
- 1, new LiteralExpression("DESCRIPTOR")));
- c->statements->Add(new ReturnStatement(TRUE_VALUE));
- stub->transact_switch->cases.push_back(c);
-
- // and the proxy-side method returning the descriptor directly
- Method* getDesc = new Method;
- getDesc->modifiers = PUBLIC;
- getDesc->returnType = STRING_TYPE;
- getDesc->returnTypeDimension = 0;
- getDesc->name = "getInterfaceDescriptor";
- getDesc->statements = new StatementBlock;
- getDesc->statements->Add(new ReturnStatement(new LiteralExpression("DESCRIPTOR")));
- proxy->elements.push_back(getDesc);
-}
-
-static Class*
-generate_interface_class(const interface_type* iface)
-{
- InterfaceType* interfaceType = static_cast<InterfaceType*>(
- NAMES.Find(iface->package, iface->name.data));
-
- // the interface class
- Class* interface = new Class;
- interface->comment = gather_comments(iface->comments_token->extra);
- interface->modifiers = PUBLIC;
- interface->what = Class::INTERFACE;
- interface->type = interfaceType;
- interface->interfaces.push_back(IINTERFACE_TYPE);
-
- // the stub inner class
- StubClass* stub = new StubClass(
- NAMES.Find(iface->package, append(iface->name.data, ".Stub").c_str()),
- interfaceType);
- interface->elements.push_back(stub);
-
- // the proxy inner class
- ProxyClass* proxy = new ProxyClass(
- NAMES.Find(iface->package,
- append(iface->name.data, ".Stub.Proxy").c_str()),
- interfaceType);
- stub->elements.push_back(proxy);
-
- // stub and proxy support for getInterfaceDescriptor()
- generate_interface_descriptors(stub, proxy);
-
- // all the declared methods of the interface
- int index = 0;
- interface_item_type* item = iface->interface_items;
- while (item != NULL) {
- if (item->item_type == METHOD_TYPE) {
- generate_method((method_type*)item, interface, stub, proxy, index);
- }
- item = item->next;
- index++;
- }
-
- return interface;
-}
-
+// =================================================
int
generate_java(const string& filename, const string& originalSrc,
interface_type* iface)
{
+ Class* cl;
+
+ if (iface->document_item.item_type == INTERFACE_TYPE_BINDER) {
+ cl = generate_binder_interface_class(iface);
+ }
+ else if (iface->document_item.item_type == INTERFACE_TYPE_RPC) {
+ cl = generate_rpc_interface_class(iface);
+ }
+
Document* document = new Document;
document->comment = "";
if (iface->package) document->package = iface->package;
document->originalSrc = originalSrc;
- document->classes.push_back(generate_interface_class(iface));
+ document->classes.push_back(cl);
// printf("outputting... filename=%s\n", filename.c_str());
FILE* to;
diff --git a/tools/aidl/generate_java.h b/tools/aidl/generate_java.h
index 203fe23..4bfcfeb 100644
--- a/tools/aidl/generate_java.h
+++ b/tools/aidl/generate_java.h
@@ -2,6 +2,7 @@
#define GENERATE_JAVA_H
#include "aidl_language.h"
+#include "AST.h"
#include <string>
@@ -10,5 +11,23 @@
int generate_java(const string& filename, const string& originalSrc,
interface_type* iface);
+Class* generate_binder_interface_class(const interface_type* iface);
+Class* generate_rpc_interface_class(const interface_type* iface);
+
+string gather_comments(extra_text_type* extra);
+string append(const char* a, const char* b);
+
+class VariableFactory
+{
+public:
+ VariableFactory(const string& base); // base must be short
+ Variable* Get(Type* type);
+ Variable* Get(int index);
+private:
+ vector<Variable*> m_vars;
+ string m_base;
+ int m_index;
+};
+
#endif // GENERATE_JAVA_H
diff --git a/tools/aidl/generate_java_binder.cpp b/tools/aidl/generate_java_binder.cpp
new file mode 100644
index 0000000..2e459a8
--- /dev/null
+++ b/tools/aidl/generate_java_binder.cpp
@@ -0,0 +1,559 @@
+#include "generate_java.h"
+#include "Type.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+// =================================================
+class StubClass : public Class
+{
+public:
+ StubClass(Type* type, Type* interfaceType);
+ virtual ~StubClass();
+
+ Variable* transact_code;
+ Variable* transact_data;
+ Variable* transact_reply;
+ Variable* transact_flags;
+ SwitchStatement* transact_switch;
+private:
+ void make_as_interface(Type* interfaceType);
+};
+
+StubClass::StubClass(Type* type, Type* interfaceType)
+ :Class()
+{
+ this->comment = "/** Local-side IPC implementation stub class. */";
+ this->modifiers = PUBLIC | ABSTRACT | STATIC;
+ this->what = Class::CLASS;
+ this->type = type;
+ this->extends = BINDER_NATIVE_TYPE;
+ this->interfaces.push_back(interfaceType);
+
+ // descriptor
+ Field* descriptor = new Field(STATIC | FINAL | PRIVATE,
+ new Variable(STRING_TYPE, "DESCRIPTOR"));
+ descriptor->value = "\"" + interfaceType->QualifiedName() + "\"";
+ this->elements.push_back(descriptor);
+
+ // ctor
+ Method* ctor = new Method;
+ ctor->modifiers = PUBLIC;
+ ctor->comment = "/** Construct the stub at attach it to the "
+ "interface. */";
+ ctor->name = "Stub";
+ ctor->statements = new StatementBlock;
+ MethodCall* attach = new MethodCall(THIS_VALUE, "attachInterface",
+ 2, THIS_VALUE, new LiteralExpression("DESCRIPTOR"));
+ ctor->statements->Add(attach);
+ this->elements.push_back(ctor);
+
+ // asInterface
+ make_as_interface(interfaceType);
+
+ // asBinder
+ Method* asBinder = new Method;
+ asBinder->modifiers = PUBLIC;
+ asBinder->returnType = IBINDER_TYPE;
+ asBinder->name = "asBinder";
+ asBinder->statements = new StatementBlock;
+ asBinder->statements->Add(new ReturnStatement(THIS_VALUE));
+ this->elements.push_back(asBinder);
+
+ // onTransact
+ this->transact_code = new Variable(INT_TYPE, "code");
+ this->transact_data = new Variable(PARCEL_TYPE, "data");
+ this->transact_reply = new Variable(PARCEL_TYPE, "reply");
+ this->transact_flags = new Variable(INT_TYPE, "flags");
+ Method* onTransact = new Method;
+ onTransact->modifiers = PUBLIC | OVERRIDE;
+ onTransact->returnType = BOOLEAN_TYPE;
+ onTransact->name = "onTransact";
+ onTransact->parameters.push_back(this->transact_code);
+ onTransact->parameters.push_back(this->transact_data);
+ onTransact->parameters.push_back(this->transact_reply);
+ onTransact->parameters.push_back(this->transact_flags);
+ onTransact->statements = new StatementBlock;
+ onTransact->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
+ this->elements.push_back(onTransact);
+ this->transact_switch = new SwitchStatement(this->transact_code);
+
+ onTransact->statements->Add(this->transact_switch);
+ MethodCall* superCall = new MethodCall(SUPER_VALUE, "onTransact", 4,
+ this->transact_code, this->transact_data,
+ this->transact_reply, this->transact_flags);
+ onTransact->statements->Add(new ReturnStatement(superCall));
+}
+
+StubClass::~StubClass()
+{
+}
+
+void
+StubClass::make_as_interface(Type *interfaceType)
+{
+ Variable* obj = new Variable(IBINDER_TYPE, "obj");
+
+ Method* m = new Method;
+ m->comment = "/**\n * Cast an IBinder object into an ";
+ m->comment += interfaceType->QualifiedName();
+ m->comment += " interface,\n";
+ m->comment += " * generating a proxy if needed.\n */";
+ m->modifiers = PUBLIC | STATIC;
+ m->returnType = interfaceType;
+ m->name = "asInterface";
+ m->parameters.push_back(obj);
+ m->statements = new StatementBlock;
+
+ IfStatement* ifstatement = new IfStatement();
+ ifstatement->expression = new Comparison(obj, "==", NULL_VALUE);
+ ifstatement->statements = new StatementBlock;
+ ifstatement->statements->Add(new ReturnStatement(NULL_VALUE));
+ m->statements->Add(ifstatement);
+
+ // IInterface iin = obj.queryLocalInterface(DESCRIPTOR)
+ MethodCall* queryLocalInterface = new MethodCall(obj, "queryLocalInterface");
+ queryLocalInterface->arguments.push_back(new LiteralExpression("DESCRIPTOR"));
+ IInterfaceType* iinType = new IInterfaceType();
+ Variable *iin = new Variable(iinType, "iin");
+ VariableDeclaration* iinVd = new VariableDeclaration(iin, queryLocalInterface, iinType);
+ m->statements->Add(iinVd);
+
+ // Ensure the instance type of the local object is as expected.
+ // One scenario where this is needed is if another package (with a
+ // different class loader) runs in the same process as the service.
+
+ // if (iin != null && iin instanceof <interfaceType>) return (<interfaceType>) iin;
+ Comparison* iinNotNull = new Comparison(iin, "!=", NULL_VALUE);
+ Comparison* instOfCheck = new Comparison(iin, " instanceof ",
+ new LiteralExpression(interfaceType->QualifiedName()));
+ IfStatement* instOfStatement = new IfStatement();
+ instOfStatement->expression = new Comparison(iinNotNull, "&&", instOfCheck);
+ instOfStatement->statements = new StatementBlock;
+ instOfStatement->statements->Add(new ReturnStatement(new Cast(interfaceType, iin)));
+ m->statements->Add(instOfStatement);
+
+ string proxyType = interfaceType->QualifiedName();
+ proxyType += ".Stub.Proxy";
+ NewExpression* ne = new NewExpression(NAMES.Find(proxyType));
+ ne->arguments.push_back(obj);
+ m->statements->Add(new ReturnStatement(ne));
+
+ this->elements.push_back(m);
+}
+
+
+
+// =================================================
+class ProxyClass : public Class
+{
+public:
+ ProxyClass(Type* type, InterfaceType* interfaceType);
+ virtual ~ProxyClass();
+
+ Variable* mRemote;
+ bool mOneWay;
+};
+
+ProxyClass::ProxyClass(Type* type, InterfaceType* interfaceType)
+ :Class()
+{
+ this->modifiers = PRIVATE | STATIC;
+ this->what = Class::CLASS;
+ this->type = type;
+ this->interfaces.push_back(interfaceType);
+
+ mOneWay = interfaceType->OneWay();
+
+ // IBinder mRemote
+ mRemote = new Variable(IBINDER_TYPE, "mRemote");
+ this->elements.push_back(new Field(PRIVATE, mRemote));
+
+ // Proxy()
+ Variable* remote = new Variable(IBINDER_TYPE, "remote");
+ Method* ctor = new Method;
+ ctor->name = "Proxy";
+ ctor->statements = new StatementBlock;
+ ctor->parameters.push_back(remote);
+ ctor->statements->Add(new Assignment(mRemote, remote));
+ this->elements.push_back(ctor);
+
+ // IBinder asBinder()
+ Method* asBinder = new Method;
+ asBinder->modifiers = PUBLIC;
+ asBinder->returnType = IBINDER_TYPE;
+ asBinder->name = "asBinder";
+ asBinder->statements = new StatementBlock;
+ asBinder->statements->Add(new ReturnStatement(mRemote));
+ this->elements.push_back(asBinder);
+}
+
+ProxyClass::~ProxyClass()
+{
+}
+
+// =================================================
+static void
+generate_new_array(Type* t, StatementBlock* addTo, Variable* v,
+ Variable* parcel)
+{
+ Variable* len = new Variable(INT_TYPE, v->name + "_length");
+ addTo->Add(new VariableDeclaration(len, new MethodCall(parcel, "readInt")));
+ IfStatement* lencheck = new IfStatement();
+ lencheck->expression = new Comparison(len, "<", new LiteralExpression("0"));
+ lencheck->statements->Add(new Assignment(v, NULL_VALUE));
+ lencheck->elseif = new IfStatement();
+ lencheck->elseif->statements->Add(new Assignment(v,
+ new NewArrayExpression(t, len)));
+ addTo->Add(lencheck);
+}
+
+static void
+generate_write_to_parcel(Type* t, StatementBlock* addTo, Variable* v,
+ Variable* parcel, int flags)
+{
+ if (v->dimension == 0) {
+ t->WriteToParcel(addTo, v, parcel, flags);
+ }
+ if (v->dimension == 1) {
+ t->WriteArrayToParcel(addTo, v, parcel, flags);
+ }
+}
+
+static void
+generate_create_from_parcel(Type* t, StatementBlock* addTo, Variable* v,
+ Variable* parcel, Variable** cl)
+{
+ if (v->dimension == 0) {
+ t->CreateFromParcel(addTo, v, parcel, cl);
+ }
+ if (v->dimension == 1) {
+ t->CreateArrayFromParcel(addTo, v, parcel, cl);
+ }
+}
+
+static void
+generate_read_from_parcel(Type* t, StatementBlock* addTo, Variable* v,
+ Variable* parcel, Variable** cl)
+{
+ if (v->dimension == 0) {
+ t->ReadFromParcel(addTo, v, parcel, cl);
+ }
+ if (v->dimension == 1) {
+ t->ReadArrayFromParcel(addTo, v, parcel, cl);
+ }
+}
+
+
+static void
+generate_method(const method_type* method, Class* interface,
+ StubClass* stubClass, ProxyClass* proxyClass, int index)
+{
+ arg_type* arg;
+ int i;
+ bool hasOutParams = false;
+
+ const bool oneway = proxyClass->mOneWay || method->oneway;
+
+ // == the TRANSACT_ constant =============================================
+ string transactCodeName = "TRANSACTION_";
+ transactCodeName += method->name.data;
+
+ char transactCodeValue[50];
+ sprintf(transactCodeValue, "(android.os.IBinder.FIRST_CALL_TRANSACTION + %d)", index);
+
+ Field* transactCode = new Field(STATIC | FINAL,
+ new Variable(INT_TYPE, transactCodeName));
+ transactCode->value = transactCodeValue;
+ stubClass->elements.push_back(transactCode);
+
+ // == the declaration in the interface ===================================
+ Method* decl = new Method;
+ decl->comment = gather_comments(method->comments_token->extra);
+ decl->modifiers = PUBLIC;
+ decl->returnType = NAMES.Search(method->type.type.data);
+ decl->returnTypeDimension = method->type.dimension;
+ decl->name = method->name.data;
+
+ arg = method->args;
+ while (arg != NULL) {
+ decl->parameters.push_back(new Variable(
+ NAMES.Search(arg->type.type.data), arg->name.data,
+ arg->type.dimension));
+ arg = arg->next;
+ }
+
+ decl->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
+
+ interface->elements.push_back(decl);
+
+ // == the stub method ====================================================
+
+ Case* c = new Case(transactCodeName);
+
+ MethodCall* realCall = new MethodCall(THIS_VALUE, method->name.data);
+
+ // interface token validation is the very first thing we do
+ c->statements->Add(new MethodCall(stubClass->transact_data,
+ "enforceInterface", 1, new LiteralExpression("DESCRIPTOR")));
+
+ // args
+ Variable* cl = NULL;
+ VariableFactory stubArgs("_arg");
+ arg = method->args;
+ while (arg != NULL) {
+ Type* t = NAMES.Search(arg->type.type.data);
+ Variable* v = stubArgs.Get(t);
+ v->dimension = arg->type.dimension;
+
+ c->statements->Add(new VariableDeclaration(v));
+
+ if (convert_direction(arg->direction.data) & IN_PARAMETER) {
+ generate_create_from_parcel(t, c->statements, v,
+ stubClass->transact_data, &cl);
+ } else {
+ if (arg->type.dimension == 0) {
+ c->statements->Add(new Assignment(v, new NewExpression(v->type)));
+ }
+ else if (arg->type.dimension == 1) {
+ generate_new_array(v->type, c->statements, v,
+ stubClass->transact_data);
+ }
+ else {
+ fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__,
+ __LINE__);
+ }
+ }
+
+ realCall->arguments.push_back(v);
+
+ arg = arg->next;
+ }
+
+ // the real call
+ Variable* _result = NULL;
+ if (0 == strcmp(method->type.type.data, "void")) {
+ c->statements->Add(realCall);
+
+ if (!oneway) {
+ // report that there were no exceptions
+ MethodCall* ex = new MethodCall(stubClass->transact_reply,
+ "writeNoException", 0);
+ c->statements->Add(ex);
+ }
+ } else {
+ _result = new Variable(decl->returnType, "_result",
+ decl->returnTypeDimension);
+ c->statements->Add(new VariableDeclaration(_result, realCall));
+
+ if (!oneway) {
+ // report that there were no exceptions
+ MethodCall* ex = new MethodCall(stubClass->transact_reply,
+ "writeNoException", 0);
+ c->statements->Add(ex);
+ }
+
+ // marshall the return value
+ generate_write_to_parcel(decl->returnType, c->statements, _result,
+ stubClass->transact_reply,
+ Type::PARCELABLE_WRITE_RETURN_VALUE);
+ }
+
+ // out parameters
+ i = 0;
+ arg = method->args;
+ while (arg != NULL) {
+ Type* t = NAMES.Search(arg->type.type.data);
+ Variable* v = stubArgs.Get(i++);
+
+ if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
+ generate_write_to_parcel(t, c->statements, v,
+ stubClass->transact_reply,
+ Type::PARCELABLE_WRITE_RETURN_VALUE);
+ hasOutParams = true;
+ }
+
+ arg = arg->next;
+ }
+
+ // return true
+ c->statements->Add(new ReturnStatement(TRUE_VALUE));
+ stubClass->transact_switch->cases.push_back(c);
+
+ // == the proxy method ===================================================
+ Method* proxy = new Method;
+ proxy->comment = gather_comments(method->comments_token->extra);
+ proxy->modifiers = PUBLIC;
+ proxy->returnType = NAMES.Search(method->type.type.data);
+ proxy->returnTypeDimension = method->type.dimension;
+ proxy->name = method->name.data;
+ proxy->statements = new StatementBlock;
+ arg = method->args;
+ while (arg != NULL) {
+ proxy->parameters.push_back(new Variable(
+ NAMES.Search(arg->type.type.data), arg->name.data,
+ arg->type.dimension));
+ arg = arg->next;
+ }
+ proxy->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
+ proxyClass->elements.push_back(proxy);
+
+ // the parcels
+ Variable* _data = new Variable(PARCEL_TYPE, "_data");
+ proxy->statements->Add(new VariableDeclaration(_data,
+ new MethodCall(PARCEL_TYPE, "obtain")));
+ Variable* _reply = NULL;
+ if (!oneway) {
+ _reply = new Variable(PARCEL_TYPE, "_reply");
+ proxy->statements->Add(new VariableDeclaration(_reply,
+ new MethodCall(PARCEL_TYPE, "obtain")));
+ }
+
+ // the return value
+ _result = NULL;
+ if (0 != strcmp(method->type.type.data, "void")) {
+ _result = new Variable(proxy->returnType, "_result",
+ method->type.dimension);
+ proxy->statements->Add(new VariableDeclaration(_result));
+ }
+
+ // try and finally
+ TryStatement* tryStatement = new TryStatement();
+ proxy->statements->Add(tryStatement);
+ FinallyStatement* finallyStatement = new FinallyStatement();
+ proxy->statements->Add(finallyStatement);
+
+ // the interface identifier token: the DESCRIPTOR constant, marshalled as a string
+ tryStatement->statements->Add(new MethodCall(_data, "writeInterfaceToken",
+ 1, new LiteralExpression("DESCRIPTOR")));
+
+ // the parameters
+ arg = method->args;
+ while (arg != NULL) {
+ Type* t = NAMES.Search(arg->type.type.data);
+ Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
+ int dir = convert_direction(arg->direction.data);
+ if (dir == OUT_PARAMETER && arg->type.dimension != 0) {
+ IfStatement* checklen = new IfStatement();
+ checklen->expression = new Comparison(v, "==", NULL_VALUE);
+ checklen->statements->Add(new MethodCall(_data, "writeInt", 1,
+ new LiteralExpression("-1")));
+ checklen->elseif = new IfStatement();
+ checklen->elseif->statements->Add(new MethodCall(_data, "writeInt",
+ 1, new FieldVariable(v, "length")));
+ tryStatement->statements->Add(checklen);
+ }
+ else if (dir & IN_PARAMETER) {
+ generate_write_to_parcel(t, tryStatement->statements, v, _data, 0);
+ }
+ arg = arg->next;
+ }
+
+ // the transact call
+ MethodCall* call = new MethodCall(proxyClass->mRemote, "transact", 4,
+ new LiteralExpression("Stub." + transactCodeName),
+ _data, _reply ? _reply : NULL_VALUE,
+ new LiteralExpression(
+ oneway ? "android.os.IBinder.FLAG_ONEWAY" : "0"));
+ tryStatement->statements->Add(call);
+
+ // throw back exceptions.
+ if (_reply) {
+ MethodCall* ex = new MethodCall(_reply, "readException", 0);
+ tryStatement->statements->Add(ex);
+ }
+
+ // returning and cleanup
+ if (_reply != NULL) {
+ if (_result != NULL) {
+ generate_create_from_parcel(proxy->returnType,
+ tryStatement->statements, _result, _reply, &cl);
+ }
+
+ // the out/inout parameters
+ arg = method->args;
+ while (arg != NULL) {
+ Type* t = NAMES.Search(arg->type.type.data);
+ Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
+ if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
+ generate_read_from_parcel(t, tryStatement->statements,
+ v, _reply, &cl);
+ }
+ arg = arg->next;
+ }
+
+ finallyStatement->statements->Add(new MethodCall(_reply, "recycle"));
+ }
+ finallyStatement->statements->Add(new MethodCall(_data, "recycle"));
+
+ if (_result != NULL) {
+ proxy->statements->Add(new ReturnStatement(_result));
+ }
+}
+
+static void
+generate_interface_descriptors(StubClass* stub, ProxyClass* proxy)
+{
+ // the interface descriptor transaction handler
+ Case* c = new Case("INTERFACE_TRANSACTION");
+ c->statements->Add(new MethodCall(stub->transact_reply, "writeString",
+ 1, new LiteralExpression("DESCRIPTOR")));
+ c->statements->Add(new ReturnStatement(TRUE_VALUE));
+ stub->transact_switch->cases.push_back(c);
+
+ // and the proxy-side method returning the descriptor directly
+ Method* getDesc = new Method;
+ getDesc->modifiers = PUBLIC;
+ getDesc->returnType = STRING_TYPE;
+ getDesc->returnTypeDimension = 0;
+ getDesc->name = "getInterfaceDescriptor";
+ getDesc->statements = new StatementBlock;
+ getDesc->statements->Add(new ReturnStatement(new LiteralExpression("DESCRIPTOR")));
+ proxy->elements.push_back(getDesc);
+}
+
+Class*
+generate_binder_interface_class(const interface_type* iface)
+{
+ InterfaceType* interfaceType = static_cast<InterfaceType*>(
+ NAMES.Find(iface->package, iface->name.data));
+
+ // the interface class
+ Class* interface = new Class;
+ interface->comment = gather_comments(iface->comments_token->extra);
+ interface->modifiers = PUBLIC;
+ interface->what = Class::INTERFACE;
+ interface->type = interfaceType;
+ interface->interfaces.push_back(IINTERFACE_TYPE);
+
+ // the stub inner class
+ StubClass* stub = new StubClass(
+ NAMES.Find(iface->package, append(iface->name.data, ".Stub").c_str()),
+ interfaceType);
+ interface->elements.push_back(stub);
+
+ // the proxy inner class
+ ProxyClass* proxy = new ProxyClass(
+ NAMES.Find(iface->package,
+ append(iface->name.data, ".Stub.Proxy").c_str()),
+ interfaceType);
+ stub->elements.push_back(proxy);
+
+ // stub and proxy support for getInterfaceDescriptor()
+ generate_interface_descriptors(stub, proxy);
+
+ // all the declared methods of the interface
+ int index = 0;
+ interface_item_type* item = iface->interface_items;
+ while (item != NULL) {
+ if (item->item_type == METHOD_TYPE) {
+ generate_method((method_type*)item, interface, stub, proxy, index);
+ }
+ item = item->next;
+ index++;
+ }
+
+ return interface;
+}
+
diff --git a/tools/aidl/generate_java_rpc.cpp b/tools/aidl/generate_java_rpc.cpp
new file mode 100644
index 0000000..ecff3a1
--- /dev/null
+++ b/tools/aidl/generate_java_rpc.cpp
@@ -0,0 +1,998 @@
+#include "generate_java.h"
+#include "Type.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+Type* SERVICE_CONTEXT_TYPE = new Type("android.content",
+ "Context", Type::BUILT_IN, false, false, false);
+Type* PRESENTER_BASE_TYPE = new Type("com.android.athome.connector",
+ "EventListener", Type::BUILT_IN, false, false, false);
+Type* PRESENTER_LISTENER_BASE_TYPE = new Type("com.android.athome.connector",
+ "EventListener.Listener", Type::BUILT_IN, false, false, false);
+Type* RPC_BROKER_TYPE = new Type("com.android.athome.connector", "Broker",
+ Type::BUILT_IN, false, false, false);
+Type* RPC_CONTAINER_TYPE = new Type("com.android.athome.connector", "ConnectorContainer",
+ Type::BUILT_IN, false, false, false);
+Type* PLACE_INFO_TYPE = new Type("android.support.place.connector", "PlaceInfo",
+ Type::BUILT_IN, false, false, false);
+// TODO: Just use Endpoint, so this works for all endpoints.
+Type* RPC_CONNECTOR_TYPE = new Type("com.android.athome.connector", "Connector",
+ Type::BUILT_IN, false, false, false);
+Type* RPC_ENDPOINT_INFO_TYPE = new UserDataType("com.android.athome.rpc",
+ "EndpointInfo", true, __FILE__, __LINE__);
+Type* RPC_RESULT_HANDLER_TYPE = new UserDataType("com.android.athome.rpc", "RpcResultHandler",
+ true, __FILE__, __LINE__);
+Type* RPC_ERROR_LISTENER_TYPE = new Type("com.android.athome.rpc", "RpcErrorHandler",
+ Type::BUILT_IN, false, false, false);
+Type* RPC_CONTEXT_TYPE = new UserDataType("com.android.athome.rpc", "RpcContext", true,
+ __FILE__, __LINE__);
+
+static void generate_create_from_data(Type* t, StatementBlock* addTo, const string& key,
+ Variable* v, Variable* data, Variable** cl);
+static void generate_new_array(Type* t, StatementBlock* addTo, Variable* v, Variable* from);
+static void generate_write_to_data(Type* t, StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data);
+
+static string
+format_int(int n)
+{
+ char str[20];
+ sprintf(str, "%d", n);
+ return string(str);
+}
+
+static string
+class_name_leaf(const string& str)
+{
+ string::size_type pos = str.rfind('.');
+ if (pos == string::npos) {
+ return str;
+ } else {
+ return string(str, pos+1);
+ }
+}
+
+static string
+results_class_name(const string& n)
+{
+ string str = n;
+ str[0] = toupper(str[0]);
+ str.insert(0, "On");
+ return str;
+}
+
+static string
+results_method_name(const string& n)
+{
+ string str = n;
+ str[0] = toupper(str[0]);
+ str.insert(0, "on");
+ return str;
+}
+
+static string
+push_method_name(const string& n)
+{
+ string str = n;
+ str[0] = toupper(str[0]);
+ str.insert(0, "push");
+ return str;
+}
+
+// =================================================
+class DispatcherClass : public Class
+{
+public:
+ DispatcherClass(const interface_type* iface, Expression* target);
+ virtual ~DispatcherClass();
+
+ void AddMethod(const method_type* method);
+ void DoneWithMethods();
+
+ Method* processMethod;
+ Variable* actionParam;
+ Variable* requestParam;
+ Variable* rpcContextParam;
+ Variable* errorParam;
+ Variable* requestData;
+ Variable* resultData;
+ IfStatement* dispatchIfStatement;
+ Expression* targetExpression;
+
+private:
+ void generate_process();
+};
+
+DispatcherClass::DispatcherClass(const interface_type* iface, Expression* target)
+ :Class(),
+ dispatchIfStatement(NULL),
+ targetExpression(target)
+{
+ generate_process();
+}
+
+DispatcherClass::~DispatcherClass()
+{
+}
+
+void
+DispatcherClass::generate_process()
+{
+ // byte[] process(String action, byte[] params, RpcContext context, RpcError status)
+ this->processMethod = new Method;
+ this->processMethod->modifiers = PUBLIC;
+ this->processMethod->returnType = BYTE_TYPE;
+ this->processMethod->returnTypeDimension = 1;
+ this->processMethod->name = "process";
+ this->processMethod->statements = new StatementBlock;
+
+ this->actionParam = new Variable(STRING_TYPE, "action");
+ this->processMethod->parameters.push_back(this->actionParam);
+
+ this->requestParam = new Variable(BYTE_TYPE, "requestParam", 1);
+ this->processMethod->parameters.push_back(this->requestParam);
+
+ this->rpcContextParam = new Variable(RPC_CONTEXT_TYPE, "context", 0);
+ this->processMethod->parameters.push_back(this->rpcContextParam);
+
+ this->errorParam = new Variable(RPC_ERROR_TYPE, "errorParam", 0);
+ this->processMethod->parameters.push_back(this->errorParam);
+
+ this->requestData = new Variable(RPC_DATA_TYPE, "request");
+ this->processMethod->statements->Add(new VariableDeclaration(requestData,
+ new NewExpression(RPC_DATA_TYPE, 1, this->requestParam)));
+
+ this->resultData = new Variable(RPC_DATA_TYPE, "resultData");
+ this->processMethod->statements->Add(new VariableDeclaration(this->resultData,
+ NULL_VALUE));
+}
+
+void
+DispatcherClass::AddMethod(const method_type* method)
+{
+ arg_type* arg;
+
+ // The if/switch statement
+ IfStatement* ifs = new IfStatement();
+ ifs->expression = new MethodCall(new StringLiteralExpression(method->name.data), "equals",
+ 1, this->actionParam);
+ StatementBlock* block = ifs->statements = new StatementBlock;
+ if (this->dispatchIfStatement == NULL) {
+ this->dispatchIfStatement = ifs;
+ this->processMethod->statements->Add(dispatchIfStatement);
+ } else {
+ this->dispatchIfStatement->elseif = ifs;
+ this->dispatchIfStatement = ifs;
+ }
+
+ // The call to decl (from above)
+ MethodCall* realCall = new MethodCall(this->targetExpression, method->name.data);
+
+ // args
+ Variable* classLoader = NULL;
+ VariableFactory stubArgs("_arg");
+ arg = method->args;
+ while (arg != NULL) {
+ Type* t = NAMES.Search(arg->type.type.data);
+ Variable* v = stubArgs.Get(t);
+ v->dimension = arg->type.dimension;
+
+ // Unmarshall the parameter
+ block->Add(new VariableDeclaration(v));
+ if (convert_direction(arg->direction.data) & IN_PARAMETER) {
+ generate_create_from_data(t, block, arg->name.data, v,
+ this->requestData, &classLoader);
+ } else {
+ if (arg->type.dimension == 0) {
+ block->Add(new Assignment(v, new NewExpression(v->type)));
+ }
+ else if (arg->type.dimension == 1) {
+ generate_new_array(v->type, block, v, this->requestData);
+ }
+ else {
+ fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__,
+ __LINE__);
+ }
+ }
+
+ // Add that parameter to the method call
+ realCall->arguments.push_back(v);
+
+ arg = arg->next;
+ }
+
+ // Add a final parameter: RpcContext. Contains data about
+ // incoming request (e.g., certificate)
+ realCall->arguments.push_back(new Variable(RPC_CONTEXT_TYPE, "context", 0));
+
+ Type* returnType = NAMES.Search(method->type.type.data);
+ if (returnType == EVENT_FAKE_TYPE) {
+ returnType = VOID_TYPE;
+ }
+
+ // the real call
+ bool first = true;
+ Variable* _result = NULL;
+ if (returnType == VOID_TYPE) {
+ block->Add(realCall);
+ } else {
+ _result = new Variable(returnType, "_result",
+ method->type.dimension);
+ block->Add(new VariableDeclaration(_result, realCall));
+
+ // need the result RpcData
+ if (first) {
+ block->Add(new Assignment(this->resultData,
+ new NewExpression(RPC_DATA_TYPE)));
+ first = false;
+ }
+
+ // marshall the return value
+ generate_write_to_data(returnType, block,
+ new StringLiteralExpression("_result"), _result, this->resultData);
+ }
+
+ // out parameters
+ int i = 0;
+ arg = method->args;
+ while (arg != NULL) {
+ Type* t = NAMES.Search(arg->type.type.data);
+ Variable* v = stubArgs.Get(i++);
+
+ if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
+ // need the result RpcData
+ if (first) {
+ block->Add(new Assignment(this->resultData, new NewExpression(RPC_DATA_TYPE)));
+ first = false;
+ }
+
+ generate_write_to_data(t, block, new StringLiteralExpression(arg->name.data),
+ v, this->resultData);
+ }
+
+ arg = arg->next;
+ }
+}
+
+void
+DispatcherClass::DoneWithMethods()
+{
+ if (this->dispatchIfStatement == NULL) {
+ return;
+ }
+
+ this->elements.push_back(this->processMethod);
+
+ IfStatement* fallthrough = new IfStatement();
+ fallthrough->statements = new StatementBlock;
+ fallthrough->statements->Add(new ReturnStatement(
+ new MethodCall(SUPER_VALUE, "process", 4,
+ this->actionParam, this->requestParam,
+ this->rpcContextParam,
+ this->errorParam)));
+ this->dispatchIfStatement->elseif = fallthrough;
+ IfStatement* s = new IfStatement;
+ s->statements = new StatementBlock;
+ this->processMethod->statements->Add(s);
+ s->expression = new Comparison(this->resultData, "!=", NULL_VALUE);
+ s->statements->Add(new ReturnStatement(new MethodCall(this->resultData, "serialize")));
+ s->elseif = new IfStatement;
+ s = s->elseif;
+ s->statements->Add(new ReturnStatement(NULL_VALUE));
+}
+
+// =================================================
+class RpcProxyClass : public Class
+{
+public:
+ RpcProxyClass(const interface_type* iface, InterfaceType* interfaceType);
+ virtual ~RpcProxyClass();
+
+ Variable* endpoint;
+ Variable* broker;
+
+private:
+ void generate_ctor();
+ void generate_get_endpoint_info();
+};
+
+RpcProxyClass::RpcProxyClass(const interface_type* iface, InterfaceType* interfaceType)
+ :Class()
+{
+ this->comment = gather_comments(iface->comments_token->extra);
+ this->modifiers = PUBLIC;
+ this->what = Class::CLASS;
+ this->type = interfaceType;
+
+ // broker
+ this->broker = new Variable(RPC_BROKER_TYPE, "_broker");
+ this->elements.push_back(new Field(PRIVATE, this->broker));
+ // endpoint
+ this->endpoint = new Variable(RPC_ENDPOINT_INFO_TYPE, "_endpoint");
+ this->elements.push_back(new Field(PRIVATE, this->endpoint));
+
+ // methods
+ generate_ctor();
+ generate_get_endpoint_info();
+}
+
+RpcProxyClass::~RpcProxyClass()
+{
+}
+
+void
+RpcProxyClass::generate_ctor()
+{
+ Variable* broker = new Variable(RPC_BROKER_TYPE, "broker");
+ Variable* endpoint = new Variable(RPC_ENDPOINT_INFO_TYPE, "endpoint");
+ Method* ctor = new Method;
+ ctor->modifiers = PUBLIC;
+ ctor->name = class_name_leaf(this->type->Name());
+ ctor->statements = new StatementBlock;
+ ctor->parameters.push_back(broker);
+ ctor->parameters.push_back(endpoint);
+ this->elements.push_back(ctor);
+
+ ctor->statements->Add(new Assignment(this->broker, broker));
+ ctor->statements->Add(new Assignment(this->endpoint, endpoint));
+}
+
+void
+RpcProxyClass::generate_get_endpoint_info()
+{
+ Method* get = new Method;
+ get->modifiers = PUBLIC;
+ get->returnType = RPC_ENDPOINT_INFO_TYPE;
+ get->name = "getEndpointInfo";
+ get->statements = new StatementBlock;
+ this->elements.push_back(get);
+
+ get->statements->Add(new ReturnStatement(this->endpoint));
+}
+
+// =================================================
+class EventListenerClass : public DispatcherClass
+{
+public:
+ EventListenerClass(const interface_type* iface, Type* listenerType);
+ virtual ~EventListenerClass();
+
+ Variable* _listener;
+
+private:
+ void generate_ctor();
+};
+
+Expression*
+generate_get_listener_expression(Type* cast)
+{
+ return new Cast(cast, new MethodCall(THIS_VALUE, "getView"));
+}
+
+EventListenerClass::EventListenerClass(const interface_type* iface, Type* listenerType)
+ :DispatcherClass(iface, new FieldVariable(THIS_VALUE, "_listener"))
+{
+ this->modifiers = PRIVATE;
+ this->what = Class::CLASS;
+ this->type = new Type(iface->package ? iface->package : "",
+ append(iface->name.data, ".Presenter"),
+ Type::GENERATED, false, false, false);
+ this->extends = PRESENTER_BASE_TYPE;
+
+ this->_listener = new Variable(listenerType, "_listener");
+ this->elements.push_back(new Field(PRIVATE, this->_listener));
+
+ // methods
+ generate_ctor();
+}
+
+EventListenerClass::~EventListenerClass()
+{
+}
+
+void
+EventListenerClass::generate_ctor()
+{
+ Variable* broker = new Variable(RPC_BROKER_TYPE, "broker");
+ Variable* listener = new Variable(this->_listener->type, "listener");
+ Method* ctor = new Method;
+ ctor->modifiers = PUBLIC;
+ ctor->name = class_name_leaf(this->type->Name());
+ ctor->statements = new StatementBlock;
+ ctor->parameters.push_back(broker);
+ ctor->parameters.push_back(listener);
+ this->elements.push_back(ctor);
+
+ ctor->statements->Add(new MethodCall("super", 2, broker, listener));
+ ctor->statements->Add(new Assignment(this->_listener, listener));
+}
+
+// =================================================
+class ListenerClass : public Class
+{
+public:
+ ListenerClass(const interface_type* iface);
+ virtual ~ListenerClass();
+
+ bool needed;
+
+private:
+ void generate_ctor();
+};
+
+ListenerClass::ListenerClass(const interface_type* iface)
+ :Class(),
+ needed(false)
+{
+ this->comment = "/** Extend this to listen to the events from this class. */";
+ this->modifiers = STATIC | PUBLIC ;
+ this->what = Class::CLASS;
+ this->type = new Type(iface->package ? iface->package : "",
+ append(iface->name.data, ".Listener"),
+ Type::GENERATED, false, false, false);
+ this->extends = PRESENTER_LISTENER_BASE_TYPE;
+}
+
+ListenerClass::~ListenerClass()
+{
+}
+
+// =================================================
+class EndpointBaseClass : public DispatcherClass
+{
+public:
+ EndpointBaseClass(const interface_type* iface);
+ virtual ~EndpointBaseClass();
+
+ bool needed;
+
+private:
+ void generate_ctor();
+};
+
+EndpointBaseClass::EndpointBaseClass(const interface_type* iface)
+ :DispatcherClass(iface, THIS_VALUE),
+ needed(false)
+{
+ this->comment = "/** Extend this to implement a link service. */";
+ this->modifiers = STATIC | PUBLIC | ABSTRACT;
+ this->what = Class::CLASS;
+ this->type = new Type(iface->package ? iface->package : "",
+ append(iface->name.data, ".EndpointBase"),
+ Type::GENERATED, false, false, false);
+ this->extends = RPC_CONNECTOR_TYPE;
+
+ // methods
+ generate_ctor();
+}
+
+EndpointBaseClass::~EndpointBaseClass()
+{
+}
+
+void
+EndpointBaseClass::generate_ctor()
+{
+ Variable* container = new Variable(RPC_CONTAINER_TYPE, "container");
+ Variable* broker = new Variable(RPC_BROKER_TYPE, "broker");
+ Variable* place = new Variable(PLACE_INFO_TYPE, "placeInfo");
+ Method* ctor = new Method;
+ ctor->modifiers = PUBLIC;
+ ctor->name = class_name_leaf(this->type->Name());
+ ctor->statements = new StatementBlock;
+ ctor->parameters.push_back(container);
+ ctor->parameters.push_back(broker);
+ ctor->parameters.push_back(place);
+ this->elements.push_back(ctor);
+
+ ctor->statements->Add(new MethodCall("super", 3, container, broker, place));
+}
+
+// =================================================
+class ResultDispatcherClass : public Class
+{
+public:
+ ResultDispatcherClass();
+ virtual ~ResultDispatcherClass();
+
+ void AddMethod(int index, const string& name, Method** method, Variable** param);
+
+ bool needed;
+ Variable* methodId;
+ Variable* callback;
+ Method* onResultMethod;
+ Variable* resultParam;
+ SwitchStatement* methodSwitch;
+
+private:
+ void generate_ctor();
+ void generate_onResult();
+};
+
+ResultDispatcherClass::ResultDispatcherClass()
+ :Class(),
+ needed(false)
+{
+ this->modifiers = PRIVATE | FINAL;
+ this->what = Class::CLASS;
+ this->type = new Type("_ResultDispatcher", Type::GENERATED, false, false, false);
+ this->interfaces.push_back(RPC_RESULT_HANDLER_TYPE);
+
+ // methodId
+ this->methodId = new Variable(INT_TYPE, "methodId");
+ this->elements.push_back(new Field(PRIVATE, this->methodId));
+ this->callback = new Variable(OBJECT_TYPE, "callback");
+ this->elements.push_back(new Field(PRIVATE, this->callback));
+
+ // methods
+ generate_ctor();
+ generate_onResult();
+}
+
+ResultDispatcherClass::~ResultDispatcherClass()
+{
+}
+
+void
+ResultDispatcherClass::generate_ctor()
+{
+ Variable* methodIdParam = new Variable(INT_TYPE, "methId");
+ Variable* callbackParam = new Variable(OBJECT_TYPE, "cbObj");
+ Method* ctor = new Method;
+ ctor->modifiers = PUBLIC;
+ ctor->name = class_name_leaf(this->type->Name());
+ ctor->statements = new StatementBlock;
+ ctor->parameters.push_back(methodIdParam);
+ ctor->parameters.push_back(callbackParam);
+ this->elements.push_back(ctor);
+
+ ctor->statements->Add(new Assignment(this->methodId, methodIdParam));
+ ctor->statements->Add(new Assignment(this->callback, callbackParam));
+}
+
+void
+ResultDispatcherClass::generate_onResult()
+{
+ this->onResultMethod = new Method;
+ this->onResultMethod->modifiers = PUBLIC;
+ this->onResultMethod->returnType = VOID_TYPE;
+ this->onResultMethod->returnTypeDimension = 0;
+ this->onResultMethod->name = "onResult";
+ this->onResultMethod->statements = new StatementBlock;
+ this->elements.push_back(this->onResultMethod);
+
+ this->resultParam = new Variable(BYTE_TYPE, "result", 1);
+ this->onResultMethod->parameters.push_back(this->resultParam);
+
+ this->methodSwitch = new SwitchStatement(this->methodId);
+ this->onResultMethod->statements->Add(this->methodSwitch);
+}
+
+void
+ResultDispatcherClass::AddMethod(int index, const string& name, Method** method, Variable** param)
+{
+ Method* m = new Method;
+ m->modifiers = PUBLIC;
+ m->returnType = VOID_TYPE;
+ m->returnTypeDimension = 0;
+ m->name = name;
+ m->statements = new StatementBlock;
+ *param = new Variable(BYTE_TYPE, "result", 1);
+ m->parameters.push_back(*param);
+ this->elements.push_back(m);
+ *method = m;
+
+ Case* c = new Case(format_int(index));
+ c->statements->Add(new MethodCall(new LiteralExpression("this"), name, 1, this->resultParam));
+ c->statements->Add(new Break());
+
+ this->methodSwitch->cases.push_back(c);
+}
+
+// =================================================
+static void
+generate_new_array(Type* t, StatementBlock* addTo, Variable* v, Variable* from)
+{
+ fprintf(stderr, "aidl: implement generate_new_array %s:%d\n", __FILE__, __LINE__);
+ exit(1);
+}
+
+static void
+generate_create_from_data(Type* t, StatementBlock* addTo, const string& key, Variable* v,
+ Variable* data, Variable** cl)
+{
+ Expression* k = new StringLiteralExpression(key);
+ if (v->dimension == 0) {
+ t->CreateFromRpcData(addTo, k, v, data, cl);
+ }
+ if (v->dimension == 1) {
+ //t->ReadArrayFromRpcData(addTo, v, data, cl);
+ fprintf(stderr, "aidl: implement generate_create_from_data for arrays%s:%d\n",
+ __FILE__, __LINE__);
+ }
+}
+
+static void
+generate_write_to_data(Type* t, StatementBlock* addTo, Expression* k, Variable* v, Variable* data)
+{
+ if (v->dimension == 0) {
+ t->WriteToRpcData(addTo, k, v, data, 0);
+ }
+ if (v->dimension == 1) {
+ //t->WriteArrayToParcel(addTo, v, data);
+ fprintf(stderr, "aidl: implement generate_write_to_data for arrays%s:%d\n",
+ __FILE__, __LINE__);
+ }
+}
+
+// =================================================
+static Type*
+generate_results_method(const method_type* method, RpcProxyClass* proxyClass)
+{
+ arg_type* arg;
+
+ string resultsMethodName = results_method_name(method->name.data);
+ Type* resultsInterfaceType = new Type(results_class_name(method->name.data),
+ Type::GENERATED, false, false, false);
+
+ if (!method->oneway) {
+ Class* resultsClass = new Class;
+ resultsClass->modifiers = STATIC | PUBLIC;
+ resultsClass->what = Class::INTERFACE;
+ resultsClass->type = resultsInterfaceType;
+
+ Method* resultMethod = new Method;
+ resultMethod->comment = gather_comments(method->comments_token->extra);
+ resultMethod->modifiers = PUBLIC;
+ resultMethod->returnType = VOID_TYPE;
+ resultMethod->returnTypeDimension = 0;
+ resultMethod->name = resultsMethodName;
+ if (0 != strcmp("void", method->type.type.data)) {
+ resultMethod->parameters.push_back(new Variable(NAMES.Search(method->type.type.data),
+ "_result", method->type.dimension));
+ }
+ arg = method->args;
+ while (arg != NULL) {
+ if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
+ resultMethod->parameters.push_back(new Variable(
+ NAMES.Search(arg->type.type.data), arg->name.data,
+ arg->type.dimension));
+ }
+ arg = arg->next;
+ }
+ resultsClass->elements.push_back(resultMethod);
+
+ if (resultMethod->parameters.size() > 0) {
+ proxyClass->elements.push_back(resultsClass);
+ return resultsInterfaceType;
+ }
+ }
+ //delete resultsInterfaceType;
+ return NULL;
+}
+
+static void
+generate_proxy_method(const method_type* method, RpcProxyClass* proxyClass,
+ ResultDispatcherClass* resultsDispatcherClass, Type* resultsInterfaceType, int index)
+{
+ arg_type* arg;
+ Method* proxyMethod = new Method;
+ proxyMethod->comment = gather_comments(method->comments_token->extra);
+ proxyMethod->modifiers = PUBLIC;
+ proxyMethod->returnType = VOID_TYPE;
+ proxyMethod->returnTypeDimension = 0;
+ proxyMethod->name = method->name.data;
+ proxyMethod->statements = new StatementBlock;
+ proxyClass->elements.push_back(proxyMethod);
+
+ // The local variables
+ Variable* _data = new Variable(RPC_DATA_TYPE, "_data");
+ proxyMethod->statements->Add(new VariableDeclaration(_data, new NewExpression(RPC_DATA_TYPE)));
+
+ // Add the arguments
+ arg = method->args;
+ while (arg != NULL) {
+ if (convert_direction(arg->direction.data) & IN_PARAMETER) {
+ // Function signature
+ Type* t = NAMES.Search(arg->type.type.data);
+ Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
+ proxyMethod->parameters.push_back(v);
+
+ // Input parameter marshalling
+ generate_write_to_data(t, proxyMethod->statements,
+ new StringLiteralExpression(arg->name.data), v, _data);
+ }
+ arg = arg->next;
+ }
+
+ // If there is a results interface for this class
+ Expression* resultParameter;
+ if (resultsInterfaceType != NULL) {
+ // Result interface parameter
+ Variable* resultListener = new Variable(resultsInterfaceType, "_result");
+ proxyMethod->parameters.push_back(resultListener);
+
+ // Add the results dispatcher callback
+ resultsDispatcherClass->needed = true;
+ resultParameter = new NewExpression(resultsDispatcherClass->type, 2,
+ new LiteralExpression(format_int(index)), resultListener);
+ } else {
+ resultParameter = NULL_VALUE;
+ }
+
+ // All proxy methods take an error parameter
+ Variable* errorListener = new Variable(RPC_ERROR_LISTENER_TYPE, "_errors");
+ proxyMethod->parameters.push_back(errorListener);
+
+ // Call the broker
+ proxyMethod->statements->Add(new MethodCall(new FieldVariable(THIS_VALUE, "_broker"),
+ "sendRpc", 5,
+ proxyClass->endpoint,
+ new StringLiteralExpression(method->name.data),
+ new MethodCall(_data, "serialize"),
+ resultParameter,
+ errorListener));
+}
+
+static void
+generate_result_dispatcher_method(const method_type* method,
+ ResultDispatcherClass* resultsDispatcherClass, Type* resultsInterfaceType, int index)
+{
+ arg_type* arg;
+ Method* dispatchMethod;
+ Variable* dispatchParam;
+ resultsDispatcherClass->AddMethod(index, method->name.data, &dispatchMethod, &dispatchParam);
+
+ Variable* classLoader = NULL;
+ Variable* resultData = new Variable(RPC_DATA_TYPE, "resultData");
+ dispatchMethod->statements->Add(new VariableDeclaration(resultData,
+ new NewExpression(RPC_DATA_TYPE, 1, dispatchParam)));
+
+ // The callback method itself
+ MethodCall* realCall = new MethodCall(
+ new Cast(resultsInterfaceType, new FieldVariable(THIS_VALUE, "callback")),
+ results_method_name(method->name.data));
+
+ // The return value
+ {
+ Type* t = NAMES.Search(method->type.type.data);
+ if (t != VOID_TYPE) {
+ Variable* rv = new Variable(t, "rv");
+ dispatchMethod->statements->Add(new VariableDeclaration(rv));
+ generate_create_from_data(t, dispatchMethod->statements, "_result", rv,
+ resultData, &classLoader);
+ realCall->arguments.push_back(rv);
+ }
+ }
+
+ VariableFactory stubArgs("arg");
+ arg = method->args;
+ while (arg != NULL) {
+ if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
+ // Unmarshall the results
+ Type* t = NAMES.Search(arg->type.type.data);
+ Variable* v = stubArgs.Get(t);
+ dispatchMethod->statements->Add(new VariableDeclaration(v));
+
+ generate_create_from_data(t, dispatchMethod->statements, arg->name.data, v,
+ resultData, &classLoader);
+
+ // Add the argument to the callback
+ realCall->arguments.push_back(v);
+ }
+ arg = arg->next;
+ }
+
+ // Call the callback method
+ dispatchMethod->statements->Add(realCall);
+}
+
+static void
+generate_regular_method(const method_type* method, RpcProxyClass* proxyClass,
+ EndpointBaseClass* serviceBaseClass, ResultDispatcherClass* resultsDispatcherClass,
+ int index)
+{
+ arg_type* arg;
+
+ // == the callback interface for results ================================
+ // the service base class
+ Type* resultsInterfaceType = generate_results_method(method, proxyClass);
+
+ // == the method in the proxy class =====================================
+ generate_proxy_method(method, proxyClass, resultsDispatcherClass, resultsInterfaceType, index);
+
+ // == the method in the result dispatcher class =========================
+ if (resultsInterfaceType != NULL) {
+ generate_result_dispatcher_method(method, resultsDispatcherClass, resultsInterfaceType,
+ index);
+ }
+
+ // == The abstract method that the service developers implement ==========
+ Method* decl = new Method;
+ decl->comment = gather_comments(method->comments_token->extra);
+ decl->modifiers = PUBLIC | ABSTRACT;
+ decl->returnType = NAMES.Search(method->type.type.data);
+ decl->returnTypeDimension = method->type.dimension;
+ decl->name = method->name.data;
+ arg = method->args;
+ while (arg != NULL) {
+ decl->parameters.push_back(new Variable(
+ NAMES.Search(arg->type.type.data), arg->name.data,
+ arg->type.dimension));
+ arg = arg->next;
+ }
+
+ // Add the default RpcContext param to all methods
+ decl->parameters.push_back(new Variable(RPC_CONTEXT_TYPE, "context", 0));
+
+ serviceBaseClass->elements.push_back(decl);
+
+
+ // == the dispatch method in the service base class ======================
+ serviceBaseClass->AddMethod(method);
+}
+
+static void
+generate_event_method(const method_type* method, RpcProxyClass* proxyClass,
+ EndpointBaseClass* serviceBaseClass, ListenerClass* listenerClass,
+ EventListenerClass* presenterClass, int index)
+{
+ arg_type* arg;
+ listenerClass->needed = true;
+
+ // == the push method in the service base class =========================
+ Method* push = new Method;
+ push->modifiers = PUBLIC;
+ push->name = push_method_name(method->name.data);
+ push->statements = new StatementBlock;
+ push->returnType = VOID_TYPE;
+ serviceBaseClass->elements.push_back(push);
+
+ // The local variables
+ Variable* _data = new Variable(RPC_DATA_TYPE, "_data");
+ push->statements->Add(new VariableDeclaration(_data, new NewExpression(RPC_DATA_TYPE)));
+
+ // Add the arguments
+ arg = method->args;
+ while (arg != NULL) {
+ // Function signature
+ Type* t = NAMES.Search(arg->type.type.data);
+ Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
+ push->parameters.push_back(v);
+
+ // Input parameter marshalling
+ generate_write_to_data(t, push->statements,
+ new StringLiteralExpression(arg->name.data), v, _data);
+
+ arg = arg->next;
+ }
+
+ // Send the notifications
+ push->statements->Add(new MethodCall("pushEvent", 2,
+ new StringLiteralExpression(method->name.data),
+ new MethodCall(_data, "serialize")));
+
+ // == the event callback dispatcher method ====================================
+ presenterClass->AddMethod(method);
+
+ // == the event method in the listener base class =====================
+ Method* event = new Method;
+ event->modifiers = PUBLIC;
+ event->name = method->name.data;
+ event->statements = new StatementBlock;
+ event->returnType = VOID_TYPE;
+ listenerClass->elements.push_back(event);
+ arg = method->args;
+ while (arg != NULL) {
+ event->parameters.push_back(new Variable(
+ NAMES.Search(arg->type.type.data), arg->name.data,
+ arg->type.dimension));
+ arg = arg->next;
+ }
+
+ // Add a final parameter: RpcContext. Contains data about
+ // incoming request (e.g., certificate)
+ event->parameters.push_back(new Variable(RPC_CONTEXT_TYPE, "context", 0));
+}
+
+static void
+generate_listener_methods(RpcProxyClass* proxyClass, Type* presenterType, Type* listenerType)
+{
+ // AndroidAtHomePresenter _presenter;
+ // void startListening(Listener listener) {
+ // stopListening();
+ // _presenter = new Presenter(_broker, listener);
+ // _presenter.startListening(_endpoint);
+ // }
+ // void stopListening() {
+ // if (_presenter != null) {
+ // _presenter.stopListening();
+ // }
+ // }
+
+ Variable* _presenter = new Variable(presenterType, "_presenter");
+ proxyClass->elements.push_back(new Field(PRIVATE, _presenter));
+
+ Variable* listener = new Variable(listenerType, "listener");
+
+ Method* startListeningMethod = new Method;
+ startListeningMethod->modifiers = PUBLIC;
+ startListeningMethod->returnType = VOID_TYPE;
+ startListeningMethod->name = "startListening";
+ startListeningMethod->statements = new StatementBlock;
+ startListeningMethod->parameters.push_back(listener);
+ proxyClass->elements.push_back(startListeningMethod);
+
+ startListeningMethod->statements->Add(new MethodCall(THIS_VALUE, "stopListening"));
+ startListeningMethod->statements->Add(new Assignment(_presenter,
+ new NewExpression(presenterType, 2, proxyClass->broker, listener)));
+ startListeningMethod->statements->Add(new MethodCall(_presenter,
+ "startListening", 1, proxyClass->endpoint));
+
+ Method* stopListeningMethod = new Method;
+ stopListeningMethod->modifiers = PUBLIC;
+ stopListeningMethod->returnType = VOID_TYPE;
+ stopListeningMethod->name = "stopListening";
+ stopListeningMethod->statements = new StatementBlock;
+ proxyClass->elements.push_back(stopListeningMethod);
+
+ IfStatement* ifst = new IfStatement;
+ ifst->expression = new Comparison(_presenter, "!=", NULL_VALUE);
+ stopListeningMethod->statements->Add(ifst);
+
+ ifst->statements->Add(new MethodCall(_presenter, "stopListening"));
+ ifst->statements->Add(new Assignment(_presenter, NULL_VALUE));
+}
+
+Class*
+generate_rpc_interface_class(const interface_type* iface)
+{
+ // the proxy class
+ InterfaceType* interfaceType = static_cast<InterfaceType*>(
+ NAMES.Find(iface->package, iface->name.data));
+ RpcProxyClass* proxy = new RpcProxyClass(iface, interfaceType);
+
+ // the listener class
+ ListenerClass* listener = new ListenerClass(iface);
+
+ // the presenter class
+ EventListenerClass* presenter = new EventListenerClass(iface, listener->type);
+
+ // the service base class
+ EndpointBaseClass* base = new EndpointBaseClass(iface);
+ proxy->elements.push_back(base);
+
+ // the result dispatcher
+ ResultDispatcherClass* results = new ResultDispatcherClass();
+
+ // all the declared methods of the proxy
+ int index = 0;
+ interface_item_type* item = iface->interface_items;
+ while (item != NULL) {
+ if (item->item_type == METHOD_TYPE) {
+ if (NAMES.Search(((method_type*)item)->type.type.data) == EVENT_FAKE_TYPE) {
+ generate_event_method((method_type*)item, proxy, base, listener, presenter, index);
+ } else {
+ generate_regular_method((method_type*)item, proxy, base, results, index);
+ }
+ }
+ item = item->next;
+ index++;
+ }
+ presenter->DoneWithMethods();
+ base->DoneWithMethods();
+
+ // only add this if there are methods with results / out parameters
+ if (results->needed) {
+ proxy->elements.push_back(results);
+ }
+ if (listener->needed) {
+ proxy->elements.push_back(listener);
+ proxy->elements.push_back(presenter);
+ generate_listener_methods(proxy, presenter->type, listener->type);
+ }
+
+ return proxy;
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
index db0694c..6afdfbe 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
@@ -197,6 +197,12 @@
}
@Override
+ public boolean switchToNextInputMethod(IBinder arg0, boolean arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
public void updateStatusIcon(IBinder arg0, String arg1, int arg2) throws RemoteException {
// TODO Auto-generated method stub