aboutsummaryrefslogtreecommitdiffstats
path: root/src/java/cyanogenmod/os/Concierge.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/java/cyanogenmod/os/Concierge.java')
-rw-r--r--src/java/cyanogenmod/os/Concierge.java150
1 files changed, 150 insertions, 0 deletions
diff --git a/src/java/cyanogenmod/os/Concierge.java b/src/java/cyanogenmod/os/Concierge.java
new file mode 100644
index 0000000..5d86e82
--- /dev/null
+++ b/src/java/cyanogenmod/os/Concierge.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2016 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cyanogenmod.os;
+
+import android.os.Parcel;
+
+import cyanogenmod.os.Build.CM_VERSION_CODES;
+
+/**
+ * Simply, Concierge handles your parcels and makes sure they get marshalled and unmarshalled
+ * correctly when cross IPC boundaries even when there is a version mismatch between the client
+ * sdk level and the framework implementation.
+ *
+ * <p>On incoming parcel (to be unmarshalled):
+ *
+ * <pre class="prettyprint">
+ * ParcelInfo incomingParcelInfo = Concierge.receiveParcel(incomingParcel);
+ * int parcelableVersion = incomingParcelInfo.getParcelVersion();
+ *
+ * // Do unmarshalling steps here iterating over every plausible version
+ *
+ * // Complete the process
+ * incomingParcelInfo.complete();
+ * </pre>
+ *
+ * <p>On outgoing parcel (to be marshalled):
+ *
+ * <pre class="prettyprint">
+ * ParcelInfo outgoingParcelInfo = Concierge.prepareParcel(incomingParcel);
+ *
+ * // Do marshalling steps here iterating over every plausible version
+ *
+ * // Complete the process
+ * outgoingParcelInfo.complete();
+ * </pre>
+ *
+ * {@hide} // Unhide?
+ */
+public final class Concierge {
+
+ /** Not instantiable */
+ private Concierge() {
+ // Don't instantiate
+ }
+
+ /**
+ * Since there might be a case where new versions of the cm framework use applications running
+ * old versions of the protocol (and thus old versions of this class), we need a versioning
+ * system for the parcels sent between the core framework and its sdk users.
+ *
+ * This parcelable version should be the latest version API version listed in
+ * {@link CM_VERSION_CODES}
+ * @hide
+ */
+ public static final int PARCELABLE_VERSION = CM_VERSION_CODES.ELDERBERRY;
+
+ /**
+ * Tell the concierge to receive our parcel, so we can get information from it.
+ *
+ * MUST CALL {@link ParcelInfo#complete()} AFTER UNMARSHALLING.
+ *
+ * @param parcel Incoming parcel to be unmarshalled
+ * @return {@link ParcelInfo} containing parcel information, specifically the version.
+ */
+ public static ParcelInfo receiveParcel(Parcel parcel) {
+ return new ParcelInfo(parcel);
+ }
+
+ /**
+ * Prepare a parcel for the Concierge.
+ *
+ * MUST CALL {@link ParcelInfo#complete()} AFTER MARSHALLING.
+ *
+ * @param parcel Outgoing parcel to be marshalled
+ * @return {@link ParcelInfo} containing parcel information, specifically the version.
+ */
+ public static ParcelInfo prepareParcel(Parcel parcel) {
+ return new ParcelInfo(parcel, PARCELABLE_VERSION);
+ }
+
+ public final static class ParcelInfo {
+ private Parcel mParcel;
+ private int mParcelableVersion;
+ private int mParcelableSize;
+ private int mStartPosition;
+ private int mSizePosition;
+ private boolean mCreation = false;
+
+ ParcelInfo(Parcel parcel) {
+ mCreation = false;
+ mParcel = parcel;
+ mParcelableVersion = parcel.readInt();
+ mParcelableSize = parcel.readInt();
+ mStartPosition = parcel.dataPosition();
+ }
+
+ ParcelInfo(Parcel parcel, int parcelableVersion) {
+ mCreation = true;
+ mParcel = parcel;
+ mParcelableVersion = parcelableVersion;
+
+ // Write parcelable version, make sure to define explicit changes
+ // within {@link #PARCELABLE_VERSION);
+ mParcel.writeInt(mParcelableVersion);
+
+ // Inject a placeholder that will store the parcel size from this point on
+ // (not including the size itself).
+ mSizePosition = parcel.dataPosition();
+ mParcel.writeInt(0);
+ mStartPosition = parcel.dataPosition();
+ }
+
+ /**
+ * Get the parcel version from the {@link Parcel} received by the Concierge.
+ * @return {@link #PARCELABLE_VERSION} of the {@link Parcel}
+ */
+ public int getParcelVersion() {
+ return mParcelableVersion;
+ }
+
+ /**
+ * Complete the {@link ParcelInfo} for the Concierge.
+ */
+ public void complete() {
+ if (mCreation) {
+ // Go back and write size
+ mParcelableSize = mParcel.dataPosition() - mStartPosition;
+ mParcel.setDataPosition(mSizePosition);
+ mParcel.writeInt(mParcelableSize);
+ mParcel.setDataPosition(mStartPosition + mParcelableSize);
+ } else {
+ mParcel.setDataPosition(mStartPosition + mParcelableSize);
+ }
+ }
+ }
+}