diff options
author | Mike Lockwood <lockwood@google.com> | 2012-02-10 11:50:10 -0800 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2012-02-10 11:50:10 -0800 |
commit | 11ca31729c05a5c82aa298fb52ddebbe08a26627 (patch) | |
tree | 2dccdf3b3a7e5764e0b44cd04caa8a93ec3109f0 | |
parent | adf7c11e56e84531a3f4e9097cb05db663d7d246 (diff) | |
parent | d747dc8179df3cfcc68df78ec46b93992de52eaf (diff) | |
download | frameworks_base-11ca31729c05a5c82aa298fb52ddebbe08a26627.zip frameworks_base-11ca31729c05a5c82aa298fb52ddebbe08a26627.tar.gz frameworks_base-11ca31729c05a5c82aa298fb52ddebbe08a26627.tar.bz2 |
Merge changes Id747dc81,I3a74bd36,I2395527c,I86aeb066,Ic33d5766,I7bef7390,I4b797dd8,Id3622e9e,I28087c63,Ia1c6d909,I95a766dd,I6c0236c5,Ib71287f4,I4bcbefdc,I22a7cb8d,Ie24dbeaf,I7dbc4b45,I21d524ea,Iaa5bf14e,I7db766c3,I93fcaca2,I1eb72044,I05ffbe7c,Ifdfe2ff8,Ia8f767a2
* changes:
Fix problems dispatching media button events on headless devices
Add headless mode for running the framework without the surface flinger
SettingsProvider: Allow overridding default value for Setttings.Secure.DEVICE_PROVISIONED
Load lockscreen.disabled setting on database create as well as upgrade
SystemUI: Log an error instead of throwing an exception if navigation bar is enabled in tablet UI
SettingsProvider: Add support for overriding lockscreen.disabled default value
Allow overriding default STAY_ON_WHILE_PLUGGED_IN setting value in an overlay
Disable output processing when opening serial port.
Update aidl for new Broker API.
aidl: All flattenable types now must also be parcelable.
Update aidl to new APIs.
Suport RpcData as a parcelable type.
Modified AIDL to support authentication
Fix disconnect from wired ethernet issues.
Fix PresenterClass by adding a _listener field
add presenters to aidl.
Add SerialPort.sendBreak()
Generate fallthrough for unhandled actions in RPC methods.
PhoneWindowManager: Disable boot progress dialog on headless builds
Support custom flattenable types for RPC.
SystemServer: Don't start A2DP service if audio is not enabled
Add RpcData as a built-in marshallable type.
Add the full suite of RpcData types.
Checkpoint adding @home RPC support to aidl
ActivityManager: Make sure BOOT_COMPLETED Intent is sent when running headless
26 files changed, 2427 insertions, 794 deletions
diff --git a/core/java/android/hardware/SerialPort.java b/core/java/android/hardware/SerialPort.java index 0889790..5ef122b 100644 --- a/core/java/android/hardware/SerialPort.java +++ b/core/java/android/hardware/SerialPort.java @@ -113,10 +113,18 @@ public class SerialPort { } } + /** + * 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..02e81b6 100644 --- a/core/java/android/net/EthernetDataTracker.java +++ b/core/java/android/net/EthernetDataTracker.java @@ -79,10 +79,7 @@ public class EthernetDataTracker implements NetworkStateTracker { if (up) { mTracker.reconnect(); } else { - NetworkUtils.stopDhcp(mIface); - mTracker.mNetworkInfo.setIsAvailable(false); - mTracker.mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, - null, null); + mTracker.disconnect(); } } } @@ -129,11 +126,7 @@ public class EthernetDataTracker implements NetworkStateTracker { runDhcp(); } - private void interfaceRemoved(String iface) { - if (!iface.equals(mIface)) - return; - - Log.d(TAG, "Removing " + iface); + public void disconnect() { NetworkUtils.stopDhcp(mIface); @@ -147,6 +140,21 @@ public class EthernetDataTracker implements NetworkStateTracker { 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 = ""; } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 8f59484..0aad64a 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -1836,6 +1836,12 @@ public final class Settings { 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/jni/android_hardware_SerialPort.cpp b/core/jni/android_hardware_SerialPort.cpp index e67153b..7f40a5c 100644 --- a/core/jni/android_hardware_SerialPort.cpp +++ b/core/jni/android_hardware_SerialPort.cpp @@ -146,6 +146,8 @@ android_hardware_SerialPort_open(JNIEnv *env, jobject thiz, jobject fileDescript 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 */ @@ -234,6 +236,13 @@ android_hardware_SerialPort_write_direct(JNIEnv *env, jobject thiz, jobject buff 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}, @@ -246,6 +255,7 @@ static JNINativeMethod method_table[] = { (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) 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 @@ struct offsets_t { jfieldID ydpi; }; static offsets_t offsets; +static bool headless = false; // ---------------------------------------------------------------------------- @@ -51,10 +53,19 @@ static void android_view_Display_init( 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 void android_view_Display_init( 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_getRawWidthNative( 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_getRawHeightNative( 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_getOrientation( static jint android_view_Display_getDisplayCount( JNIEnv* env, jclass clazz) { + if (headless) return 1; return SurfaceComposerClient::getNumberOfDisplays(); } @@ -113,6 +128,12 @@ static JNINativeMethod gMethods[] = { 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/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml index 4ea2c31..f7713aa 100644 --- a/packages/SettingsProvider/res/values/defaults.xml +++ b/packages/SettingsProvider/res/values/defaults.xml @@ -70,6 +70,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 +143,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..3ebf44b 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 @@ public class DatabaseHelper extends SQLiteOpenHelper { // 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 @@ public class DatabaseHelper extends SQLiteOpenHelper { } 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 @@ public class DatabaseHelper extends SQLiteOpenHelper { 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,12 @@ public class DatabaseHelper extends SQLiteOpenHelper { 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); } finally { if (stmt != null) stmt.close(); } 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 @@ public class TabletStatusBar extends StatusBar implements // 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/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index d34ed17..1efb475 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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 { @@ -1839,7 +1844,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { * 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 +2585,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@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 +2784,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { // 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 +2819,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // 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 +3055,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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 +3123,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { mScreenOnEarly = false; mScreenOnFully = false; } - mKeyguardMediator.onScreenTurnedOff(why); + if (mKeyguardMediator != null) { + mKeyguardMediator.onScreenTurnedOff(why); + } synchronized (mLock) { updateOrientationListenerLp(); updateLockScreenTimeout(); @@ -3131,31 +3142,33 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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 +3194,20 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@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 +3219,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@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 +3481,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ public void systemReady() { - // tell the keyguard - mKeyguardMediator.onSystemReady(); + if (mKeyguardMediator != null) { + // tell the keyguard + mKeyguardMediator.onSystemReady(); + } synchronized (mLock) { updateOrientationListenerLp(); mSystemReady = true; @@ -3485,6 +3507,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@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 +3671,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { public void run() { synchronized (this) { if (localLOGV) Log.v(TAG, "mScreenLockTimeout activating keyguard"); - mKeyguardMediator.doKeyguardTimeout(); + if (mKeyguardMediator != null) { + mKeyguardMediator.doKeyguardTimeout(); + } mLockScreenTimerActive = false; } } @@ -3662,7 +3687,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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 +3888,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java index bb0ac3e..7974951 100644 --- a/services/java/com/android/server/PowerManagerService.java +++ b/services/java/com/android/server/PowerManagerService.java @@ -50,6 +50,7 @@ import android.os.PowerManager; 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 @@ public class PowerManagerService extends IPowerManager.Stub 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 @@ public class PowerManagerService extends IPowerManager.Stub 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 @@ public class PowerManagerService extends IPowerManager.Stub } 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) { diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index d132949..e9fcecc 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -108,6 +108,7 @@ class ServerThread extends Thread { 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; @@ -232,10 +233,13 @@ class ServerThread extends Thread { 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); @@ -459,8 +463,10 @@ class ServerThread extends Thread { try { Slog.i(TAG, "Wallpaper Service"); - wallpaper = new WallpaperManagerService(context); - ServiceManager.addService(Context.WALLPAPER_SERVICE, wallpaper); + if (!headless) { + wallpaper = new WallpaperManagerService(context); + ServiceManager.addService(Context.WALLPAPER_SERVICE, wallpaper); + } } catch (Throwable e) { reportWtf("starting Wallpaper Service", e); } @@ -652,7 +658,7 @@ class ServerThread extends Thread { 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/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 8071459..5a70dcf 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -268,7 +268,9 @@ public final class ActivityManagerService extends ActivityManagerNative static final String[] EMPTY_STRING_ARRAY = new String[0]; public ActivityStack mMainStack; - + + private final boolean mHeadless; + /** * Description of a request to start a new activity, which has been held * due to app switches being disabled. @@ -2307,6 +2309,7 @@ public final class ActivityManagerService extends ActivityManagerNative 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); @@ -2866,6 +2869,13 @@ public final class ActivityManagerService extends ActivityManagerNative } 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 @@ -4710,7 +4720,9 @@ public final class ActivityManagerService extends ActivityManagerNative 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) { @@ -13809,6 +13821,9 @@ public final class ActivityManagerService extends ActivityManagerNative */ 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; 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 @@ public class WindowManagerService extends IWindowManager.Stub 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 @@ public class WindowManagerService extends IWindowManager.Stub */ 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 @@ public class WindowManagerService extends IWindowManager.Stub 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 class WindowManagerService extends IWindowManager.Stub public void performBootTimeout() { synchronized(mWindowMap) { - if (mDisplayEnabled) { + if (mDisplayEnabled || mHeadless) { return; } Slog.w(TAG, "***** BOOT TIMEOUT: forcing display enabled"); @@ -5057,6 +5061,8 @@ public class WindowManagerService extends IWindowManager.Stub // 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/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 @@ LiteralExpression::Write(FILE* to) 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) { } +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) { } +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 @@ SwitchStatement::Write(FILE* to) 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 @@ Method::Write(FILE* to) 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 @@ struct LiteralExpression : public Expression 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 @@ struct Statement virtual void Write(FILE* to) = 0; }; -struct StatementBlock +struct StatementBlock : public Statement { vector<Statement*> statements; @@ -146,6 +156,7 @@ struct MethodCall : public Expression 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 @@ struct NewExpression : public Expression 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 @@ struct SwitchStatement : public Statement 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 @@ LOCAL_SRC_FILES := \ 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..b84b3c4 100755 --- a/tools/aidl/Type.cpp +++ b/tools/aidl/Type.cpp @@ -11,6 +11,7 @@ Type* LONG_TYPE; 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_NATIVE_TYPE; 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 @@ Expression* FALSE_VALUE; 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 @@ register_base_types() 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 @@ register_base_types() 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 @@ make_generic_type(const string& package, const string& name, // ================================================================ -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) { @@ -244,6 +274,26 @@ Type::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, } 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 +314,35 @@ Type::BuildWriteToParcelFlags(int flags) // ================================================================ -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 +354,40 @@ BasicType::CanBeArray() const 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 +431,24 @@ BooleanType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* p 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 +490,24 @@ CharType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parc 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 +554,24 @@ StringType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* pa 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 +631,7 @@ CharSequenceType::CreateFromParcel(StatementBlock* addTo, Variable* v, // ================================================================ RemoteExceptionType::RemoteExceptionType() - :Type("android.os", "RemoteException", BUILT_IN, false, false) + :Type("android.os", "RemoteException", BUILT_IN, false, false, false) { } @@ -540,7 +650,7 @@ RemoteExceptionType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variab // ================================================================ RuntimeExceptionType::RuntimeExceptionType() - :Type("java.lang", "RuntimeException", BUILT_IN, false, false) + :Type("java.lang", "RuntimeException", BUILT_IN, false, false, false) { } @@ -560,7 +670,7 @@ RuntimeExceptionType::CreateFromParcel(StatementBlock* addTo, Variable* v, Varia // ================================================================ IBinderType::IBinderType() - :Type("android.os", "IBinder", BUILT_IN, true, false) + :Type("android.os", "IBinder", BUILT_IN, true, false, false) { } @@ -599,7 +709,7 @@ IBinderType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* p // ================================================================ IInterfaceType::IInterfaceType() - :Type("android.os", "IInterface", BUILT_IN, false, false) + :Type("android.os", "IInterface", BUILT_IN, false, false, false) { } @@ -619,7 +729,7 @@ IInterfaceType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* p // ================================================================ BinderType::BinderType() - :Type("android.os", "Binder", BUILT_IN, false, false) + :Type("android.os", "Binder", BUILT_IN, false, false, false) { } @@ -640,7 +750,7 @@ BinderType::CreateFromParcel(StatementBlock* addTo, Variable* v, // ================================================================ BinderProxyType::BinderProxyType() - :Type("android.os", "BinderProxy", BUILT_IN, false, false) + :Type("android.os", "BinderProxy", BUILT_IN, false, false, false) { } @@ -661,7 +771,7 @@ BinderProxyType::CreateFromParcel(StatementBlock* addTo, Variable* v, // ================================================================ ParcelType::ParcelType() - :Type("android.os", "Parcel", BUILT_IN, false, false) + :Type("android.os", "Parcel", BUILT_IN, false, false, false) { } @@ -680,7 +790,7 @@ ParcelType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parce // ================================================================ ParcelableInterfaceType::ParcelableInterfaceType() - :Type("android.os", "Parcelable", BUILT_IN, false, false) + :Type("android.os", "Parcelable", BUILT_IN, false, false, false) { } @@ -699,7 +809,7 @@ ParcelableInterfaceType::CreateFromParcel(StatementBlock* addTo, Variable* v, Va // ================================================================ MapType::MapType() - :Type("java.util", "Map", BUILT_IN, true, true) + :Type("java.util", "Map", BUILT_IN, true, false, true) { } @@ -729,8 +839,7 @@ MapType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, } 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 +849,7 @@ MapType::ReadFromParcel(StatementBlock* addTo, Variable* v, // ================================================================ ListType::ListType() - :Type("java.util", "List", BUILT_IN, true, true) + :Type("java.util", "List", BUILT_IN, true, true, true) { } @@ -771,24 +880,38 @@ ListType::ReadFromParcel(StatementBlock* addTo, Variable* v, 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"; } 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 +934,7 @@ ParcelableType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parc } 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 +955,7 @@ ParcelableType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* p } 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 +971,20 @@ ParcelableType::ReadFromParcel(StatementBlock* addTo, Variable* v, } 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 +993,67 @@ ParcelableType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v, } 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) +{ + // if (v != null) { + // RpcData _obj = new RpcData(); + // v.writeToRpcData(_obj); + // data.putRpcData(k, obj); + // } + IfStatement* ifpart = new IfStatement; + ifpart->expression = new Comparison(v, "!=", NULL_VALUE); + Variable* _obj = new Variable(RPC_DATA_TYPE, "_obj"); + ifpart->statements->Add(new VariableDeclaration(_obj, new NewExpression(RPC_DATA_TYPE))); + ifpart->statements->Add(new MethodCall(v, "writeToRpcData", 1, _obj)); + ifpart->statements->Add(new MethodCall(data, "putRpcData", 2, k, _obj)); + + addTo->Add(ifpart); +} + +void +UserDataType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, + Variable* data, Variable** cl) +{ + // RpcData _obj_XX = data.getRpcData(k); + // if (_data_XX != null) + // v = CLASS.RPC_CREATOR.createFromParcel(parcel) + // } else { + // v = null; + // } + + StatementBlock* block = new StatementBlock; + addTo->Add(block); + + Variable* _obj = new Variable(RPC_DATA_TYPE, "_obj"); + block->Add(new VariableDeclaration(_obj, new MethodCall(data, "getRpcData", 1, k))); + + IfStatement* ifpart = new IfStatement(); + ifpart->expression = new Comparison(_obj, "!=", NULL_VALUE); + ifpart->statements->Add(new Assignment(v, + new MethodCall(v->type, "RPC_CREATOR.createFromRpcData", 1, data))); + + IfStatement* elsepart = new IfStatement(); + ifpart->elseif = elsepart; + elsepart->statements->Add(new Assignment(v, NULL_VALUE)); + + block->Add(ifpart); +} // ================================================================ 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 +1092,7 @@ InterfaceType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* pa 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 +1112,12 @@ GenericType::GenericType(const string& package, const string& name, SetQualifiedName(m_importName + gen); } +const vector<Type*>& +GenericType::GenericArgumentTypes() const +{ + return m_args; +} + string GenericType::GenericArguments() const { @@ -1041,10 +1217,50 @@ GenericListType::ReadFromParcel(StatementBlock* addTo, Variable* v, } } +void +GenericListType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v, + Variable* data, int flags) +{ + addTo->Add(new MethodCall(data, "putList", 2, k, v)); +} + +void +GenericListType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, + Variable* data, Variable** cl) +{ + 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..f2f3f21 100755 --- a/tools/aidl/Type.h +++ b/tools/aidl/Type.h @@ -13,7 +13,7 @@ public: // kinds enum { BUILT_IN, - PARCELABLE, + USERDATA, INTERFACE, GENERATED }; @@ -24,9 +24,9 @@ public: }; 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,7 +36,8 @@ public: 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; @@ -59,6 +60,11 @@ public: 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 +80,24 @@ private: 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 +113,22 @@ public: 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 +149,11 @@ public: 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 +174,11 @@ public: 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 +202,11 @@ public: 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,13 +343,19 @@ public: 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; @@ -330,6 +374,11 @@ public: 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 +406,7 @@ public: 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 +424,22 @@ private: 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 +457,15 @@ public: 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 +503,13 @@ extern Namespace NAMES; 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 +522,13 @@ extern Type* BINDER_PROXY_TYPE; 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..e5689b9 100644 --- a/tools/aidl/aidl.cpp +++ b/tools/aidl/aidl.cpp @@ -29,7 +29,7 @@ static void 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 @@ test_document(document_item_type* d) } 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 @@ check_filenames(const char* filename, document_item_type* items) { 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 @@ kind_to_string(int kind) { 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 @@ gather_types(const char* filename, document_item_type* items) 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 @@ gather_types(const char* filename, document_item_type* items) 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 @@ gather_types(const char* filename, document_item_type* items) 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 @@ matches_keyword(const char* str) } 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 @@ check_method(const char* filename, method_type* m) 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,8 +459,16 @@ check_method(const char* filename, method_type* m) 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); @@ -479,7 +517,7 @@ check_method(const char* filename, method_type* m) // 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 +535,9 @@ check_types(const char* filename, document_item_type* items) { 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 +546,7 @@ check_types(const char* filename, document_item_type* items) 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 +583,29 @@ exactly_one_interface(const char* filename, const document_item_type* items, con 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 +640,7 @@ generate_dep_file(const Options& options, const document_item_type* items) 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 +700,12 @@ static string 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 +776,40 @@ parse_preprocessed_file(const string& filename) 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 +981,14 @@ preprocess_aidl(const Options& options) } 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 +1058,3 @@ main(int argc, const char **argv) fprintf(stderr, "aidl: internal error\n"); return 1; } - - diff --git a/tools/aidl/aidl_language.h b/tools/aidl/aidl_language.h index 9ca5deb..f203dbb 100644 --- a/tools/aidl/aidl_language.h +++ b/tools/aidl/aidl_language.h @@ -63,8 +63,9 @@ typedef struct method_type { } 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 @@ typedef struct document_item_type { 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 @@ typedef union lexer_type { 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 @@ brackets \[{whitespace}?\] /* 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 @@ static int count_brackets(const char*); %token ARRAY %token PARCELABLE %token INTERFACE +%token FLATTENABLE +%token RPC %token IN %token OUT %token INOUT @@ -72,36 +74,61 @@ document_items: ; 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 @@ interface_header: } | 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 @@ interface_decl: 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 @@ VariableFactory::Get(int index) } // ================================================= -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 @@ gather_comments(extra_text_type* extra) return s; } -static string +string append(const char* a, const char* b) { string s = a; @@ -257,379 +56,25 @@ append(const char* a, const char* b) 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) +// ================================================= +int +generate_java(const string& filename, const string& originalSrc, + interface_type* iface) { - if (v->dimension == 0) { - t->CreateFromParcel(addTo, v, parcel, cl); - } - if (v->dimension == 1) { - t->CreateArrayFromParcel(addTo, v, parcel, cl); - } -} + Class* 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); + if (iface->document_item.item_type == INTERFACE_TYPE_BINDER) { + cl = generate_binder_interface_class(iface); } -} - - -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; + else if (iface->document_item.item_type == INTERFACE_TYPE_RPC) { + cl = generate_rpc_interface_class(iface); } - 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) -{ 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 @@ using namespace std; 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..e4867e4 --- /dev/null +++ b/tools/aidl/generate_java_rpc.cpp @@ -0,0 +1,977 @@ +#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); +// 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(); +}; + +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(); +} + +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)); +} + +// ================================================= +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"); + 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); + this->elements.push_back(ctor); + + ctor->statements->Add(new MethodCall("super", 2, container, broker)); +} + +// ================================================= +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); + 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; +} |