Merge changes from topic "cas_aidl" am: 9d7488c540 am: bf30bc6187 am: 2de678e695

Original change: https://android-review.googlesource.com/c/platform/hardware/interfaces/+/2222080

Change-Id: I0c40f9ec8f86411bdb2762977f65154e6c1985f6
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Henry Fang
2022-10-25 18:01:33 +00:00
committed by Automerger Merge Worker
49 changed files with 3675 additions and 0 deletions

31
cas/aidl/Android.bp Normal file
View File

@@ -0,0 +1,31 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
aidl_interface {
name: "android.hardware.cas",
vendor_available: true,
srcs: ["android/hardware/cas/*.aidl"],
stability: "vintf",
imports: ["android.hardware.common-V2"],
backend: {
cpp: {
enabled: false,
},
java: {
sdk_version: "module_current",
},
},
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.cas;
@VintfStability
parcelable AidlCasPluginDescriptor {
int caSystemId;
String name;
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.cas;
@VintfStability
union DestinationBuffer {
android.hardware.cas.SharedBuffer nonsecureMemory;
android.hardware.common.NativeHandle secureMemory;
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.cas;
@VintfStability
interface ICas {
void closeSession(in byte[] sessionId);
byte[] openSession(in android.hardware.cas.SessionIntent intent, in android.hardware.cas.ScramblingMode mode);
void processEcm(in byte[] sessionId, in byte[] ecm);
void processEmm(in byte[] emm);
void provision(in String provisionString);
void refreshEntitlements(in int refreshType, in byte[] refreshData);
void release();
void sendEvent(in int event, in int arg, in byte[] eventData);
void sendSessionEvent(in byte[] sessionId, in int event, in int arg, in byte[] eventData);
void setPrivateData(in byte[] pvtData);
void setSessionPrivateData(in byte[] sessionId, in byte[] pvtData);
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.cas;
@VintfStability
interface ICasListener {
void onEvent(in int event, in int arg, in byte[] data);
void onSessionEvent(in byte[] sessionId, in int event, in int arg, in byte[] data);
void onStatusUpdate(in android.hardware.cas.StatusEvent event, in int number);
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.cas;
@VintfStability
interface IDescrambler {
int descramble(in android.hardware.cas.ScramblingControl scramblingControl, in android.hardware.cas.SubSample[] subSamples, in android.hardware.cas.SharedBuffer srcBuffer, in long srcOffset, in android.hardware.cas.DestinationBuffer dstBuffer, in long dstOffset);
void release();
boolean requiresSecureDecoderComponent(in String mime);
void setMediaCasSession(in byte[] sessionId);
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.cas;
@VintfStability
interface IMediaCasService {
android.hardware.cas.IDescrambler createDescrambler(in int CA_system_id);
android.hardware.cas.ICas createPlugin(in int CA_system_id, in android.hardware.cas.ICasListener listener);
android.hardware.cas.AidlCasPluginDescriptor[] enumeratePlugins();
boolean isDescramblerSupported(in int CA_system_id);
boolean isSystemIdSupported(in int CA_system_id);
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.cas;
@Backing(type="int") @VintfStability
enum ScramblingControl {
UNSCRAMBLED = 0,
RESERVED = 1,
EVENKEY = 2,
ODDKEY = 3,
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.cas;
@Backing(type="int") @VintfStability
enum ScramblingMode {
RESERVED = 0,
DVB_CSA1 = 1,
DVB_CSA2 = 2,
DVB_CSA3_STANDARD = 3,
DVB_CSA3_MINIMAL = 4,
DVB_CSA3_ENHANCE = 5,
DVB_CISSA_V1 = 6,
DVB_IDSA = 7,
MULTI2 = 8,
AES128 = 9,
AES_CBC = 10,
AES_ECB = 11,
AES_SCTE52 = 12,
TDES_ECB = 13,
TDES_SCTE52 = 14,
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.cas;
@Backing(type="int") @VintfStability
enum SessionIntent {
LIVE = 0,
PLAYBACK = 1,
RECORD = 2,
TIMESHIFT = 3,
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.cas;
@VintfStability
parcelable SharedBuffer {
android.hardware.common.Ashmem heapBase;
long offset;
long size;
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.cas;
@VintfStability
parcelable Status {
const int OK = 0;
const int ERROR_CAS_NO_LICENSE = -1;
const int ERROR_CAS_LICENSE_EXPIRED = -2;
const int ERROR_CAS_SESSION_NOT_OPENED = -3;
const int ERROR_CAS_CANNOT_HANDLE = -4;
const int ERROR_CAS_INVALID_STATE = -5;
const int BAD_VALUE = -6;
const int ERROR_CAS_NOT_PROVISIONED = -7;
const int ERROR_CAS_RESOURCE_BUSY = -8;
const int ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION = -9;
const int ERROR_CAS_TAMPER_DETECTED = -10;
const int ERROR_CAS_DEVICE_REVOKED = -11;
const int ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED = -12;
const int ERROR_CAS_DECRYPT = -13;
const int ERROR_CAS_UNKNOWN = -14;
const int ERROR_CAS_NEED_ACTIVATION = -15;
const int ERROR_CAS_NEED_PAIRING = -16;
const int ERROR_CAS_NO_CARD = -17;
const int ERROR_CAS_CARD_MUTE = -18;
const int ERROR_CAS_CARD_INVALID = -19;
const int ERROR_CAS_BLACKOUT = -20;
const int ERROR_CAS_REBOOTING = -21;
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.cas;
@Backing(type="byte") @VintfStability
enum StatusEvent {
PLUGIN_PHYSICAL_MODULE_CHANGED = 0,
PLUGIN_SESSION_NUMBER_CHANGED = 1,
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.cas;
@VintfStability
parcelable SubSample {
int numBytesOfClearData;
int numBytesOfEncryptedData;
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.cas;
/**
* Describes a CAS plugin with its system ID and name.
*/
@VintfStability
parcelable AidlCasPluginDescriptor {
int caSystemId;
String name;
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.cas;
import android.hardware.cas.SharedBuffer;
import android.hardware.common.NativeHandle;
@VintfStability
union DestinationBuffer {
/**
* If type == SHARED_MEMORY, the descrambled data must be written
* to user-space non-secure shared memory.
*/
SharedBuffer nonsecureMemory;
/**
* If type == NATIVE_HANDLE, the descrambled data must be written
* to secure memory referenced by the vendor's buffer allocator.
*/
NativeHandle secureMemory;
}

View File

@@ -0,0 +1,121 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.cas;
import android.hardware.cas.ScramblingMode;
import android.hardware.cas.SessionIntent;
/**
* ICas is the API to control the CAS. It is used to manage sessions, provision/refresh the cas
* system, and process the EMM/ECM messages. It also allows bi-directional, scheme-specific
* communications between the client and the cas system.
*/
@VintfStability
interface ICas {
/**
* Close a session.
*
* @param sessionId The id of the session to be closed.
*/
void closeSession(in byte[] sessionId);
/**
* Open a session to descramble one or more streams by specifying intention
* and scrambling mode.
*
* @param intent the intention of the session to be opened.
* @param mode the scrambling mode the session will use.
*
* @return sessionId The id of the newly opened session.
*/
byte[] openSession(in SessionIntent intent, in ScramblingMode mode);
/**
* Process an ECM from the ECM stream for this sessions elementary stream.
*
* @param sessionId the id of the session which the ecm data applies to.
* @param ecm a byte array containing the ecm data.
*/
void processEcm(in byte[] sessionId, in byte[] ecm);
/**
* Process an in-band EMM from the EMM stream.
*
* @param emm a byte array containing the emm data.
*/
void processEmm(in byte[] emm);
/**
* Initiate a provisioning operation for a CA system.
*
* @param provisionString string containing information needed for the
* provisioning operation, the format of which is scheme and implementation
* specific.
*/
void provision(in String provisionString);
/**
* Notify the CA system to refresh entitlement keys.
*
* @param refreshType the type of the refreshment.
* @param refreshData private data associated with the refreshment.
*/
void refreshEntitlements(in int refreshType, in byte[] refreshData);
/**
* Release the descrambler instance.
*/
void release();
/**
* Send an scheme-specific event to the CasPlugin.
*
* @param event an integer denoting a scheme-specific event to be sent.
* @param arg a scheme-specific integer argument for the event.
* @param data a byte array containing scheme-specific data for the event.
*/
void sendEvent(in int event, in int arg, in byte[] eventData);
/**
* Send an scheme-specific session event to the CasPlugin.
*
* @param sessionId the id of an opened session.
* @param event an integer denoting a scheme-specific event to be sent.
* @param arg a scheme-specific integer argument for the event.
* @param data a byte array containing scheme-specific data for the event.
*/
void sendSessionEvent(in byte[] sessionId, in int event, in int arg, in byte[] eventData);
/**
* Provide the CA private data from a CA_descriptor in the conditional
* access table to a CasPlugin.
*
* @param pvtData a byte array containing the private data, the format of
* which is scheme-specific and opaque to the framework.
*/
void setPrivateData(in byte[] pvtData);
/**
* Provide the CA private data from a CA_descriptor in the program map
* table to a session.
*
* @param sessionId the id of the session which the private data applies to.
* @param pvtData a byte array containing the private data, the format of
* which is scheme-specific and opaque to the framework.
*/
void setSessionPrivateData(in byte[] sessionId, in byte[] pvtData);
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.cas;
import android.hardware.cas.StatusEvent;
@VintfStability
interface ICasListener {
/**
* Notify the listener of a scheme-specific event from the CA system.
*
* @param event an integer whose meaning is scheme-specific.
* @param arg an integer whose meaning is scheme-specific.
* @param data a byte array of data whose format and meaning are
* scheme-specific.
*/
void onEvent(in int event, in int arg, in byte[] data);
/**
* Notify the listener of a scheme-specific session event from CA system.
*
* @param sessionId the id of an opened session.
* @param event an integer whose meaning is scheme-specific.
* @param arg an integer whose meaning is scheme-specific.
* @param data a byte array of data whose format and meaning are
* scheme-specific.
*/
void onSessionEvent(in byte[] sessionId, in int event, in int arg, in byte[] data);
/**
* Notify the listener that the status of CAS system has changed.
*
* @param event the event type of status change.
* @param number value for status event.
* For PLUGIN_PHYSICAL_MODULE_CHANGED event:
* the positive number presents how many plugins are inserted;
* the negative number presents how many plugins are removed.
* Client must enumerate plugins after receive the event.
* For PLUGIN_SESSION_NUMBER_CHANGED event:
* the number presents how many sessions are supported
* in the plugin.
*/
void onStatusUpdate(in StatusEvent event, in int number);
}

View File

@@ -0,0 +1,68 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.cas;
import android.hardware.cas.DestinationBuffer;
import android.hardware.cas.ScramblingControl;
import android.hardware.cas.SharedBuffer;
import android.hardware.cas.SubSample;
/**
* IDescrambler is the API to control the descrambling operations.
*/
@VintfStability
interface IDescrambler {
/**
* Descramble the data in a source SharedBuffer, described by an array of
* SubSample structures.
*
* @param scramblingControl an enumeration indicating the key that the subsamples
* were scrambled with.
* @param subSamples an array of SubSample structures describing the number of
* clear and scrambled bytes within each subsample.
* @param srcBuffer the SharedBuffer containing the source scrambled data.
* @param srcOffset the position where the source scrambled data starts at.
* @param dstBuffer the DestinationBuffer to hold the descrambled data.
* @param dstOffset the position where the descrambled data should start at.
*
* @return bytesWritten Number of bytes that have been successfully written.
*/
int descramble(in ScramblingControl scramblingControl, in SubSample[] subSamples,
in SharedBuffer srcBuffer, in long srcOffset, in DestinationBuffer dstBuffer,
in long dstOffset);
/**
* Release the descrambler instance.
*/
void release();
/**
* Query if the scrambling scheme requires the use of a secure decoder
* to decode data of the given mime type.
*
* @param mime the mime type of the media data.
* @return whether the descrambler requires a secure decoder.
*/
boolean requiresSecureDecoderComponent(in String mime);
/**
* Associate a MediaCas session with this MediaDescrambler instance.
*
* @param sessionId the id of the session to associate with this descrambler instance.
*/
void setMediaCasSession(in byte[] sessionId);
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.cas;
import android.hardware.cas.AidlCasPluginDescriptor;
import android.hardware.cas.ICas;
import android.hardware.cas.ICasListener;
import android.hardware.cas.IDescrambler;
/**
* IMediaCasService is the main entry point for interacting with a vendor's
* cas HAL to create cas and descrambler plugin instances. A cas plugin instance
* opens cas sessions which are used to obtain keys for a descrambler session,
* which can in turn be used to descramble protected video content.
*/
@VintfStability
interface IMediaCasService {
/**
* Construct a new instance of a DescramblerPlugin given a CA_system_id.
*
* @param CA_system_id the id of the CA system.
* @return the newly created plugin interface.
*/
IDescrambler createDescrambler(in int CA_system_id);
/**
* Construct a new instance of a CasPlugin given a CA_system_id.
*
* @param CA_system_id the id of the CA system.
* @param listener the event listener to receive events coming from the CasPlugin.
* @return the newly created CasPlugin interface.
*/
ICas createPlugin(in int CA_system_id, in ICasListener listener);
/**
* List all available CA systems on the device.
*
* @return an array of descriptors for the available CA systems.
*/
AidlCasPluginDescriptor[] enumeratePlugins();
/**
* Query if the descrambling scheme for a CA system is supported on this device.
*
* @param CA_system_id the id of the CA system.
* @return whether the specified descrambling scheme is supported on this device.
*/
boolean isDescramblerSupported(in int CA_system_id);
/**
* Query if a certain CA system is supported on this device.
*
* @param CA_system_id the id of the CA system.
* @return whether the specified CA system is supported on this device.
*/
boolean isSystemIdSupported(in int CA_system_id);
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.cas;
/**
* Enumerates the keys used to scramble the content.
*/
@VintfStability
@Backing(type="int")
enum ScramblingControl {
UNSCRAMBLED = 0,
RESERVED = 1,
EVENKEY = 2,
ODDKEY = 3,
}

View File

@@ -0,0 +1,98 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.cas;
/**
* The Scrambling Mode.
*/
@VintfStability
@Backing(type="int")
enum ScramblingMode {
RESERVED = 0,
/**
* DVB (Digital Video Broadcasting) CSA1 (Common Scrambling Algorithm 1) is
* the default mode and shall be used when the scrambling descriptor
* is not present in the program map section. DVB scrambling mode is
* specified in ETSI EN 300 468 specification.
*/
DVB_CSA1,
DVB_CSA2,
/**
* DVB-CSA3 in standard mode.
*/
DVB_CSA3_STANDARD,
/**
* DVB-CSA3 in minimally enhanced mode.
*/
DVB_CSA3_MINIMAL,
/**
* DVB-CSA3 in fully enhanced mode.
*/
DVB_CSA3_ENHANCE,
/**
* DVB-CISSA version 1.
*/
DVB_CISSA_V1,
/**
* ATIS-0800006 IIF Default Scrambling Algorithm (IDSA).
*/
DVB_IDSA,
/**
* a symmetric key algorithm.
*/
MULTI2,
/**
* Advanced Encryption System (AES) 128-bit Encryption mode.
*/
AES128,
/**
* Advanced Encryption System (AES) Cipher Block Chaining (CBC) mode.
*/
AES_CBC,
/**
* Advanced Encryption System (AES) Electronic Code Book (ECB) mode.
*/
AES_ECB,
/**
* Advanced Encryption System (AES) Society of Cable Telecommunications
* Engineers (SCTE) 52 mode.
*/
AES_SCTE52,
/**
* Triple Data Encryption Algorithm (TDES) Electronic Code Book (ECB) mode.
*/
TDES_ECB,
/**
* Triple Data Encryption Algorithm (TDES) Society of Cable Telecommunications
* Engineers (SCTE) 52 mode.
*/
TDES_SCTE52,
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.cas;
/**
* The intented usage for the session.
*/
@VintfStability
@Backing(type="int")
enum SessionIntent {
/**
* Live Stream.
*/
LIVE,
/**
* Playback Recorded Stream.
*/
PLAYBACK,
/**
* Record Live Stream.
*/
RECORD,
/**
* View the content with Time Shift capability
*/
TIMESHIFT,
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.cas;
import android.hardware.common.Ashmem;
/**
* SharedBuffer describes a shared buffer which is defined by a heapBase, an
* offset and a size. The offset is relative to the shared memory base for the
* memory region identified by heapBase.
*/
@VintfStability
parcelable SharedBuffer {
/**
* Ashmem shared memory
*/
Ashmem heapBase;
/**
* The offset from the shared memory base
*/
long offset;
/**
* The size of the shared buffer in bytes
*/
long size;
}

View File

@@ -0,0 +1,150 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.cas;
@VintfStability
parcelable Status {
/**
* The CAS plugin must return OK when an operation completes without any
* errors.
*/
const int OK = 0;
/**
* The CAS plugin must return ERROR_CAS_NO_LICENSE, when descrambling is
* attempted and no license keys have been provided.
*/
const int ERROR_CAS_NO_LICENSE = -1;
/**
* ERROR_CAS_LICENSE_EXPIRED must be returned when an attempt is made
* to use a license and the keys in that license have expired.
*/
const int ERROR_CAS_LICENSE_EXPIRED = -2;
/**
* The CAS plugin must return ERROR_CAS_SESSION_NOT_OPENED when an
* attempt is made to use a session that has not been opened.
*/
const int ERROR_CAS_SESSION_NOT_OPENED = -3;
/**
* The CAS plugin must return ERROR_CAS_CANNOT_HANDLE when an unsupported
* data format or operation is attempted.
*/
const int ERROR_CAS_CANNOT_HANDLE = -4;
/**
* ERROR_CAS_INVALID_STATE must be returned when the device is in a state
* where it is not able to perform descrambling.
*/
const int ERROR_CAS_INVALID_STATE = -5;
/**
* The CAS plugin must return BAD_VALUE whenever an illegal parameter is
* passed to one of the interface functions.
*/
const int BAD_VALUE = -6;
/**
* The CAS plugin must return ERROR_CAS_NOT_PROVISIONED when the device
* has not yet been provisioned.
*/
const int ERROR_CAS_NOT_PROVISIONED = -7;
/**
* ERROR_CAS_RESOURCE_BUSY must be returned when resources, such as CAS
* sessions or secure buffers are not available to perform a requested
* operation because they are already in use.
*/
const int ERROR_CAS_RESOURCE_BUSY = -8;
/**
* The CAS Plugin must return ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION
* when the output protection level enabled on the device is not
* sufficient to meet the requirements in the license policy. HDCP is an
* example of a form of output protection.
*/
const int ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION = -9;
/**
* The CAS Plugin must return ERROR_CAS_TAMPER_DETECTED if an attempt to
* tamper with the CAS system is detected.
*/
const int ERROR_CAS_TAMPER_DETECTED = -10;
/**
* The CAS Plugin must return ERROR_CAS_DEVICE_REVOKED if the response
* indicates that the device has been revoked. Device revocation means
* that the device is no longer permitted to play content.
*/
const int ERROR_CAS_DEVICE_REVOKED = -11;
/**
* The CAS plugin must return ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED when
* descrambling is failing because the session is not initialized properly.
*/
const int ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED = -12;
/**
* The CAS Plugin must return ERROR_CAS_DECRYPT if the DescramblerPlugin's
* descramble operation fails.
*/
const int ERROR_CAS_DECRYPT = -13;
/**
* ERROR_CAS_UNKNOWN must be returned when a fatal failure occurs and no
* other defined error is appropriate.
*/
const int ERROR_CAS_UNKNOWN = -14;
/**
* ERROR_CAS_NEED_ACTIVATION is used to trigger device activation process.
*/
const int ERROR_CAS_NEED_ACTIVATION = -15;
/**
* ERROR_CAS_NEED_PAIRING is used to trigger pairing process.
*/
const int ERROR_CAS_NEED_PAIRING = -16;
/**
* ERROR_CAS_NO_CARD is used to report no smart card for descrambling.
*/
const int ERROR_CAS_NO_CARD = -17;
/**
* ERROR_CAS_CARD_MUTE is used to report smart card is muted for
* descrambling.
*/
const int ERROR_CAS_CARD_MUTE = -18;
/**
* ERROR_CAS_CARD_INVALID is used to report smart card isn't valid.
*/
const int ERROR_CAS_CARD_INVALID = -19;
/**
* ERROR_CAS_BLACKOUT is used to report geographical blackout.
*/
const int ERROR_CAS_BLACKOUT = -20;
/**
* ERROR_CAS_REBOOTING is used to report CAS is during rebooting.
*/
const int ERROR_CAS_REBOOTING = -21;
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.cas;
/**
* The Event Type for status change.
*/
@VintfStability
@Backing(type="byte")
enum StatusEvent {
/**
* The status of CAS plugin was changed due to physical module insertion or
* removal. Client must call enumeratePlugins to update plugins' status.
*/
PLUGIN_PHYSICAL_MODULE_CHANGED,
/**
* The status of supported session number was changed due to physical module
* insertion or removal. Client must update session resource according to
* latest StatusMessage from the StatusEvent. The plugin supports unlimited
* session by default.
*/
PLUGIN_SESSION_NUMBER_CHANGED,
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.cas;
/**
* A subsample consists of some number of bytes of clear (unscrambled)
* data followed by a number of bytes of scrambled data.
*/
@VintfStability
parcelable SubSample {
int numBytesOfClearData;
int numBytesOfEncryptedData;
}

93
cas/aidl/default/Android.bp Executable file
View File

@@ -0,0 +1,93 @@
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "hardware_interfaces_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["hardware_interfaces_license"],
}
cc_library_static {
name: "libcasexampleimpl",
vendor_available: true,
srcs: [
"CasImpl.cpp",
"DescramblerImpl.cpp",
"MediaCasService.cpp",
"SharedLibrary.cpp",
"TypeConvert.cpp",
],
shared_libs: [
"android.hardware.cas-V1-ndk",
"libbinder_ndk",
"liblog",
"libutils",
"libcutils",
],
static_libs: [
"libaidlcommonsupport",
],
header_libs: [
"libstagefright_foundation_headers",
"media_plugin_headers",
],
}
cc_defaults {
name: "cas_service_example_defaults",
vendor: true,
relative_install_path: "hw",
srcs: ["service.cpp"],
static_libs: [
"libaidlcommonsupport",
"libcasexampleimpl",
],
shared_libs: [
"android.hardware.cas-V1-ndk",
"libbinder_ndk",
"liblog",
"libutils",
"libcutils",
],
header_libs: ["media_plugin_headers"],
vintf_fragments: ["android.hardware.cas-service.xml"],
}
cc_binary {
name: "android.hardware.cas-service.example",
defaults: ["cas_service_example_defaults"],
init_rc: ["cas-default.rc"],
}
cc_binary {
name: "android.hardware.cas-service.example-lazy",
defaults: ["cas_service_example_defaults"],
init_rc: ["cas-default-lazy.rc"],
cflags: ["-DLAZY_SERVICE"],
}
cc_fuzz {
name: "android.hardware.cas-service_fuzzer",
vendor: true,
defaults: ["service_fuzzer_defaults"],
srcs: ["fuzzer.cpp"],
shared_libs: [
"android.hardware.cas-V1-ndk",
"libcutils",
"liblog",
],
static_libs: [
"libaidlcommonsupport",
"libcasexampleimpl",
],
header_libs: ["media_plugin_headers"],
fuzz_config: {
componentid: 1344,
},
}

242
cas/aidl/default/CasImpl.cpp Executable file
View File

@@ -0,0 +1,242 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
icensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "android.hardware.cas-CasImpl"
#include <media/cas/CasAPI.h>
#include <utils/Log.h>
#include "CasImpl.h"
#include "TypeConvert.h"
namespace aidl {
namespace android {
namespace hardware {
namespace cas {
CasImpl::CasImpl(const shared_ptr<ICasListener>& listener) : mListener(listener) {
ALOGV("CTOR");
}
CasImpl::~CasImpl() {
ALOGV("DTOR");
release();
}
// static
void CasImpl::OnEvent(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size) {
if (appData == NULL) {
ALOGE("Invalid appData!");
return;
}
CasImpl* casImpl = static_cast<CasImpl*>(appData);
casImpl->onEvent(event, arg, data, size);
}
// static
void CasImpl::CallBackExt(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size,
const CasSessionId* sessionId) {
if (appData == NULL) {
ALOGE("Invalid appData!");
return;
}
CasImpl* casImpl = static_cast<CasImpl*>(appData);
casImpl->onEvent(sessionId, event, arg, data, size);
}
// static
void CasImpl::StatusUpdate(void* appData, int32_t event, int32_t arg) {
if (appData == NULL) {
ALOGE("Invalid appData!");
return;
}
CasImpl* casImpl = static_cast<CasImpl*>(appData);
casImpl->onStatusUpdate(event, arg);
}
void CasImpl::init(CasPlugin* plugin) {
shared_ptr<CasPlugin> holder(plugin);
atomic_store(&mPluginHolder, holder);
}
void CasImpl::onEvent(int32_t event, int32_t arg, uint8_t* data, size_t size) {
if (mListener == NULL) {
return;
}
vector<uint8_t> eventData;
if (data != NULL) {
eventData.assign(data, data + size);
}
mListener->onEvent(event, arg, eventData);
}
void CasImpl::onEvent(const CasSessionId* sessionId, int32_t event, int32_t arg, uint8_t* data,
size_t size) {
if (mListener == NULL) {
return;
}
vector<uint8_t> eventData;
if (data != NULL) {
eventData.assign(data, data + size);
}
if (sessionId != NULL) {
mListener->onSessionEvent(*sessionId, event, arg, eventData);
} else {
mListener->onEvent(event, arg, eventData);
}
}
void CasImpl::onStatusUpdate(int32_t event, int32_t arg) {
if (mListener == NULL) {
return;
}
mListener->onStatusUpdate(static_cast<StatusEvent>(event), arg);
}
ScopedAStatus CasImpl::setPluginStatusUpdateCallback() {
ALOGV("%s", __FUNCTION__);
shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
if (holder.get() == nullptr) {
return toStatus(INVALID_OPERATION);
}
return toStatus(holder->setStatusCallback(&CasImpl::StatusUpdate));
}
ScopedAStatus CasImpl::setPrivateData(const vector<uint8_t>& pvtData) {
ALOGV("%s", __FUNCTION__);
shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
if (holder.get() == nullptr) {
return toStatus(INVALID_OPERATION);
}
return toStatus(holder->setPrivateData(pvtData));
}
ScopedAStatus CasImpl::openSession(SessionIntent intent, ScramblingMode mode,
vector<uint8_t>* sessionId) {
ALOGV("%s", __FUNCTION__);
shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
status_t err = INVALID_OPERATION;
if (holder.get() != nullptr) {
err = holder->openSession(static_cast<uint32_t>(intent), static_cast<uint32_t>(mode),
sessionId);
holder.reset();
}
return toStatus(err);
}
ScopedAStatus CasImpl::setSessionPrivateData(const vector<uint8_t>& sessionId,
const vector<uint8_t>& pvtData) {
ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
if (holder.get() == nullptr) {
return toStatus(INVALID_OPERATION);
}
return toStatus(holder->setSessionPrivateData(sessionId, pvtData));
}
ScopedAStatus CasImpl::closeSession(const vector<uint8_t>& sessionId) {
ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
if (holder.get() == nullptr) {
return toStatus(INVALID_OPERATION);
}
return toStatus(holder->closeSession(sessionId));
}
ScopedAStatus CasImpl::processEcm(const vector<uint8_t>& sessionId, const vector<uint8_t>& ecm) {
ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
if (holder.get() == nullptr) {
return toStatus(INVALID_OPERATION);
}
return toStatus(holder->processEcm(sessionId, ecm));
}
ScopedAStatus CasImpl::processEmm(const vector<uint8_t>& emm) {
ALOGV("%s", __FUNCTION__);
shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
if (holder.get() == nullptr) {
return toStatus(INVALID_OPERATION);
}
return toStatus(holder->processEmm(emm));
}
ScopedAStatus CasImpl::sendEvent(int32_t event, int32_t arg, const vector<uint8_t>& eventData) {
ALOGV("%s", __FUNCTION__);
shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
if (holder.get() == nullptr) {
return toStatus(INVALID_OPERATION);
}
status_t err = holder->sendEvent(event, arg, eventData);
return toStatus(err);
}
ScopedAStatus CasImpl::sendSessionEvent(const vector<uint8_t>& sessionId, int32_t event,
int32_t arg, const vector<uint8_t>& eventData) {
ALOGV("%s", __FUNCTION__);
shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
if (holder.get() == nullptr) {
return toStatus(INVALID_OPERATION);
}
status_t err = holder->sendSessionEvent(sessionId, event, arg, eventData);
return toStatus(err);
}
ScopedAStatus CasImpl::provision(const string& provisionString) {
ALOGV("%s: provisionString=%s", __FUNCTION__, provisionString.c_str());
shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
if (holder.get() == nullptr) {
return toStatus(INVALID_OPERATION);
}
return toStatus(holder->provision(String8(provisionString.c_str())));
}
ScopedAStatus CasImpl::refreshEntitlements(int32_t refreshType,
const vector<uint8_t>& refreshData) {
ALOGV("%s", __FUNCTION__);
shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
if (holder.get() == nullptr) {
return toStatus(INVALID_OPERATION);
}
status_t err = holder->refreshEntitlements(refreshType, refreshData);
return toStatus(err);
}
ScopedAStatus CasImpl::release() {
ALOGV("%s: plugin=%p", __FUNCTION__, mPluginHolder.get());
shared_ptr<CasPlugin> holder(nullptr);
atomic_store(&mPluginHolder, holder);
return ScopedAStatus::ok();
}
} // namespace cas
} // namespace hardware
} // namespace android
} // namespace aidl

93
cas/aidl/default/CasImpl.h Executable file
View File

@@ -0,0 +1,93 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <aidl/android/hardware/cas/BnCas.h>
#include <aidl/android/hardware/cas/ICasListener.h>
#include <media/stagefright/foundation/ABase.h>
namespace aidl {
namespace android {
namespace hardware {
namespace cas {
using namespace ::android;
using namespace std;
using ndk::ScopedAStatus;
class CasImpl : public BnCas {
public:
CasImpl(const shared_ptr<ICasListener>& listener);
virtual ~CasImpl();
static void OnEvent(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size);
static void CallBackExt(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size,
const CasSessionId* sessionId);
static void StatusUpdate(void* appData, int32_t event, int32_t arg);
void init(CasPlugin* plugin);
void onEvent(int32_t event, int32_t arg, uint8_t* data, size_t size);
void onEvent(const CasSessionId* sessionId, int32_t event, int32_t arg, uint8_t* data,
size_t size);
void onStatusUpdate(int32_t event, int32_t arg);
// ICas inherits
ScopedAStatus setPluginStatusUpdateCallback();
virtual ScopedAStatus setPrivateData(const vector<uint8_t>& pvtData) override;
virtual ScopedAStatus openSession(SessionIntent intent, ScramblingMode mode,
vector<uint8_t>* sessionId) override;
virtual ScopedAStatus closeSession(const vector<uint8_t>& sessionId) override;
virtual ScopedAStatus setSessionPrivateData(const vector<uint8_t>& sessionId,
const vector<uint8_t>& pvtData) override;
virtual ScopedAStatus processEcm(const vector<uint8_t>& sessionId,
const vector<uint8_t>& ecm) override;
virtual ScopedAStatus processEmm(const vector<uint8_t>& emm) override;
virtual ScopedAStatus sendEvent(int32_t event, int32_t arg,
const vector<uint8_t>& eventData) override;
virtual ScopedAStatus sendSessionEvent(const vector<uint8_t>& sessionId, int32_t event,
int32_t arg, const vector<uint8_t>& eventData) override;
virtual ScopedAStatus provision(const string& provisionString) override;
virtual ScopedAStatus refreshEntitlements(int32_t refreshType,
const vector<uint8_t>& refreshData) override;
virtual ScopedAStatus release() override;
private:
struct PluginHolder;
shared_ptr<CasPlugin> mPluginHolder;
shared_ptr<ICasListener> mListener;
DISALLOW_EVIL_CONSTRUCTORS(CasImpl);
};
} // namespace cas
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -0,0 +1,193 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "android.hardware.cas-DescramblerImpl"
#include <aidlcommonsupport/NativeHandle.h>
#include <inttypes.h>
#include <media/cas/DescramblerAPI.h>
#include <media/hardware/CryptoAPI.h>
#include <media/stagefright/foundation/AUtils.h>
#include <sys/mman.h>
#include <utils/Log.h>
#include "DescramblerImpl.h"
#include "TypeConvert.h"
namespace aidl {
namespace android {
namespace hardware {
namespace cas {
#define CHECK_SUBSAMPLE_DEF(type) \
static_assert(sizeof(SubSample) == sizeof(type::SubSample), "SubSample: size doesn't match"); \
static_assert(offsetof(SubSample, numBytesOfClearData) == \
offsetof(type::SubSample, mNumBytesOfClearData), \
"SubSample: numBytesOfClearData offset doesn't match"); \
static_assert(offsetof(SubSample, numBytesOfEncryptedData) == \
offsetof(type::SubSample, mNumBytesOfEncryptedData), \
"SubSample: numBytesOfEncryptedData offset doesn't match")
CHECK_SUBSAMPLE_DEF(DescramblerPlugin);
CHECK_SUBSAMPLE_DEF(CryptoPlugin);
DescramblerImpl::DescramblerImpl(DescramblerPlugin* plugin) : mPluginHolder(plugin) {
ALOGV("CTOR: plugin=%p", mPluginHolder.get());
}
DescramblerImpl::~DescramblerImpl() {
ALOGV("DTOR: plugin=%p", mPluginHolder.get());
release();
}
ScopedAStatus DescramblerImpl::setMediaCasSession(const vector<uint8_t>& in_sessionId) {
ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(in_sessionId).string());
shared_ptr<DescramblerPlugin> holder = atomic_load(&mPluginHolder);
if (holder.get() == nullptr) {
return toStatus(INVALID_OPERATION);
}
return toStatus(holder->setMediaCasSession(in_sessionId));
}
ScopedAStatus DescramblerImpl::requiresSecureDecoderComponent(const string& in_mime,
bool* _aidl_return) {
shared_ptr<DescramblerPlugin> holder = atomic_load(&mPluginHolder);
if (holder.get() == nullptr) {
*_aidl_return = false;
}
*_aidl_return = holder->requiresSecureDecoderComponent(String8(in_mime.c_str()));
return ScopedAStatus::ok();
}
static inline bool validateRangeForSize(int64_t offset, int64_t length, int64_t size) {
return isInRange<int64_t, uint64_t>(0, (uint64_t)size, offset, (uint64_t)length);
}
ScopedAStatus DescramblerImpl::descramble(ScramblingControl scramblingControl,
const vector<SubSample>& subSamples,
const SharedBuffer& srcBuffer, int64_t srcOffset,
const DestinationBuffer& dstBuffer, int64_t dstOffset,
int32_t* _aidl_return) {
ALOGV("%s", __FUNCTION__);
// heapbase's size is stored in int64_t, but mapMemory's mmap will map size in
// size_t. If size is over SIZE_MAX, mapMemory mapMemory could succeed but the
// mapped memory's actual size will be smaller than the reported size.
if (srcBuffer.heapBase.size > SIZE_MAX) {
ALOGE("Invalid memory size: %" PRIu64 "", srcBuffer.heapBase.size);
android_errorWriteLog(0x534e4554, "79376389");
return toStatus(BAD_VALUE);
}
void* srcPtr = mmap(NULL, srcBuffer.heapBase.size, PROT_READ | PROT_WRITE, MAP_SHARED,
srcBuffer.heapBase.fd.get(), 0);
// Validate if the offset and size in the SharedBuffer is consistent with the
// mapped heapbase, since the offset and size is controlled by client.
if (srcPtr == NULL) {
ALOGE("Failed to map src buffer.");
return toStatus(BAD_VALUE);
}
if (!validateRangeForSize(srcBuffer.offset, srcBuffer.size, srcBuffer.heapBase.size)) {
ALOGE("Invalid src buffer range: offset %" PRIu64 ", size %" PRIu64
", srcMem"
"size %" PRIu64 "",
srcBuffer.offset, srcBuffer.size, srcBuffer.heapBase.size);
android_errorWriteLog(0x534e4554, "67962232");
return toStatus(BAD_VALUE);
}
// use 64-bit here to catch bad subsample size that might be overflowing.
uint64_t totalBytesInSubSamples = 0;
for (size_t i = 0; i < subSamples.size(); i++) {
uint32_t numBytesOfClearData = subSamples[i].numBytesOfClearData;
uint32_t numBytesOfEncryptedData = subSamples[i].numBytesOfEncryptedData;
totalBytesInSubSamples += (uint64_t)numBytesOfClearData + numBytesOfEncryptedData;
}
// Further validate if the specified srcOffset and requested total subsample size
// is consistent with the source shared buffer size.
if (!validateRangeForSize(srcOffset, totalBytesInSubSamples, srcBuffer.size)) {
ALOGE("Invalid srcOffset and subsample size: "
"srcOffset %" PRIu64 ", totalBytesInSubSamples %" PRIu64
", srcBuffer"
"size %" PRIu64 "",
srcOffset, totalBytesInSubSamples, srcBuffer.size);
android_errorWriteLog(0x534e4554, "67962232");
return toStatus(BAD_VALUE);
}
srcPtr = (uint8_t*)srcPtr + srcBuffer.offset;
void* dstPtr = NULL;
if (dstBuffer.getTag() == DestinationBuffer::Tag::nonsecureMemory) {
// When using shared memory, src buffer is also used as dst,
// we don't map it again here.
dstPtr = srcPtr;
// In this case the dst and src would be the same buffer, need to validate
// dstOffset against the buffer size too.
if (!validateRangeForSize(dstOffset, totalBytesInSubSamples, srcBuffer.size)) {
ALOGE("Invalid dstOffset and subsample size: "
"dstOffset %" PRIu64 ", totalBytesInSubSamples %" PRIu64
", srcBuffer"
"size %" PRIu64 "",
dstOffset, totalBytesInSubSamples, srcBuffer.size);
android_errorWriteLog(0x534e4554, "67962232");
return toStatus(BAD_VALUE);
}
} else {
native_handle_t* handle = makeFromAidl(dstBuffer.get<DestinationBuffer::secureMemory>());
dstPtr = static_cast<void*>(handle);
}
// Get a local copy of the shared_ptr for the plugin. Note that before
// calling the callback, this shared_ptr must be manually reset, since
// the client side could proceed as soon as the callback is called
// without waiting for this method to go out of scope.
shared_ptr<DescramblerPlugin> holder = atomic_load(&mPluginHolder);
if (holder.get() == nullptr) {
return toStatus(INVALID_OPERATION);
}
// Casting SubSample to DescramblerPlugin::SubSample, but need to ensure
// structs are actually identical
auto returnStatus =
holder->descramble(dstBuffer.getTag() != DestinationBuffer::Tag::nonsecureMemory,
(DescramblerPlugin::ScramblingControl)scramblingControl,
subSamples.size(), (DescramblerPlugin::SubSample*)subSamples.data(),
srcPtr, srcOffset, dstPtr, dstOffset, NULL);
holder.reset();
*_aidl_return = returnStatus;
return toStatus(returnStatus >= 0 ? OK : returnStatus);
}
ScopedAStatus DescramblerImpl::release() {
ALOGV("%s: plugin=%p", __FUNCTION__, mPluginHolder.get());
shared_ptr<DescramblerPlugin> holder(nullptr);
atomic_store(&mPluginHolder, holder);
return ScopedAStatus::ok();
}
} // namespace cas
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -0,0 +1,56 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <aidl/android/hardware/cas/BnDescrambler.h>
#include <media/stagefright/foundation/ABase.h>
namespace aidl {
namespace android {
namespace hardware {
namespace cas {
using namespace ::android;
using namespace std;
using ndk::ScopedAStatus;
class DescramblerImpl : public BnDescrambler {
public:
DescramblerImpl(DescramblerPlugin* plugin);
virtual ~DescramblerImpl();
virtual ScopedAStatus setMediaCasSession(const vector<uint8_t>& in_sessionId) override;
virtual ScopedAStatus requiresSecureDecoderComponent(const string& in_mime,
bool* _aidl_return) override;
virtual ScopedAStatus descramble(ScramblingControl in_scramblingControl,
const vector<SubSample>& in_subSamples,
const SharedBuffer& in_srcBuffer, int64_t in_srcOffset,
const DestinationBuffer& in_dstBuffer, int64_t in_dstOffset,
int32_t* _aidl_return) override;
virtual ScopedAStatus release() override;
private:
shared_ptr<DescramblerPlugin> mPluginHolder;
DISALLOW_EVIL_CONSTRUCTORS(DescramblerImpl);
};
} // namespace cas
} // namespace hardware
} // namespace android
} // namespace aidl

219
cas/aidl/default/FactoryLoader.h Executable file
View File

@@ -0,0 +1,219 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <dirent.h>
#include <dlfcn.h>
#include <media/cas/CasAPI.h>
#include <utils/KeyedVector.h>
#include <utils/Mutex.h>
#include "SharedLibrary.h"
using namespace std;
namespace aidl {
namespace android {
namespace hardware {
namespace cas {
using namespace ::android;
template <class T>
class FactoryLoader {
public:
FactoryLoader(const char* name) : mFactory(NULL), mCreateFactoryFuncName(name) {}
virtual ~FactoryLoader() { closeFactory(); }
bool findFactoryForScheme(int32_t CA_system_id, shared_ptr<SharedLibrary>* library = NULL,
T** factory = NULL);
bool enumeratePlugins(vector<AidlCasPluginDescriptor>* results);
private:
typedef T* (*CreateFactoryFunc)();
Mutex mMapLock;
T* mFactory;
const char* mCreateFactoryFuncName;
shared_ptr<SharedLibrary> mLibrary;
KeyedVector<int32_t, String8> mCASystemIdToLibraryPathMap;
KeyedVector<String8, shared_ptr<SharedLibrary>> mLibraryPathToOpenLibraryMap;
bool loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id,
shared_ptr<SharedLibrary>* library, T** factory);
bool queryPluginsFromPath(const String8& path, vector<AidlCasPluginDescriptor>* results);
bool openFactory(const String8& path);
void closeFactory();
};
template <class T>
bool FactoryLoader<T>::findFactoryForScheme(int32_t CA_system_id,
shared_ptr<SharedLibrary>* library, T** factory) {
if (library != NULL) {
library->reset();
}
if (factory != NULL) {
*factory = NULL;
}
Mutex::Autolock autoLock(mMapLock);
// first check cache
ssize_t index = mCASystemIdToLibraryPathMap.indexOfKey(CA_system_id);
if (index >= 0) {
return loadFactoryForSchemeFromPath(mCASystemIdToLibraryPathMap[index], CA_system_id,
library, factory);
}
// no luck, have to search
#ifdef __LP64__
String8 dirPath("/vendor/lib64/mediacas");
#else
String8 dirPath("/vendor/lib/mediacas");
#endif
DIR* pDir = opendir(dirPath.string());
if (pDir == NULL) {
ALOGE("Failed to open plugin directory %s", dirPath.string());
return false;
}
struct dirent* pEntry;
while ((pEntry = readdir(pDir))) {
String8 pluginPath = dirPath + "/" + pEntry->d_name;
if (pluginPath.getPathExtension() == ".so") {
if (loadFactoryForSchemeFromPath(pluginPath, CA_system_id, library, factory)) {
mCASystemIdToLibraryPathMap.add(CA_system_id, pluginPath);
closedir(pDir);
return true;
}
}
}
closedir(pDir);
ALOGE("Failed to find plugin");
return false;
}
template <class T>
bool FactoryLoader<T>::enumeratePlugins(vector<AidlCasPluginDescriptor>* results) {
ALOGI("enumeratePlugins");
results->clear();
#ifdef __LP64__
String8 dirPath("/vendor/lib64/mediacas");
#else
String8 dirPath("/vendor/lib/mediacas");
#endif
DIR* pDir = opendir(dirPath.string());
if (pDir == NULL) {
ALOGE("Failed to open plugin directory %s", dirPath.string());
return false;
}
Mutex::Autolock autoLock(mMapLock);
struct dirent* pEntry;
while ((pEntry = readdir(pDir))) {
String8 pluginPath = dirPath + "/" + pEntry->d_name;
if (pluginPath.getPathExtension() == ".so") {
queryPluginsFromPath(pluginPath, results);
}
}
return true;
}
template <class T>
bool FactoryLoader<T>::loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id,
shared_ptr<SharedLibrary>* library,
T** factory) {
closeFactory();
if (!openFactory(path) || !mFactory->isSystemIdSupported(CA_system_id)) {
closeFactory();
return false;
}
if (library != NULL) {
*library = mLibrary;
}
if (factory != NULL) {
*factory = mFactory;
}
return true;
}
template <class T>
bool FactoryLoader<T>::queryPluginsFromPath(const String8& path,
vector<AidlCasPluginDescriptor>* results) {
closeFactory();
vector<CasPluginDescriptor> descriptors;
if (!openFactory(path) || mFactory->queryPlugins(&descriptors) != OK) {
closeFactory();
return false;
}
for (auto it = descriptors.begin(); it != descriptors.end(); it++) {
results->push_back(
AidlCasPluginDescriptor{.caSystemId = it->CA_system_id, .name = it->name.c_str()});
}
return true;
}
template <class T>
bool FactoryLoader<T>::openFactory(const String8& path) {
// get strong pointer to open shared library
ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path);
if (index >= 0) {
mLibrary = mLibraryPathToOpenLibraryMap[index];
} else {
index = mLibraryPathToOpenLibraryMap.add(path, NULL);
}
if (!mLibrary.get()) {
mLibrary = ::ndk::SharedRefBase::make<SharedLibrary>(path);
if (!*mLibrary) {
return false;
}
mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary);
}
CreateFactoryFunc createFactory = (CreateFactoryFunc)mLibrary->lookup(mCreateFactoryFuncName);
if (createFactory == NULL || (mFactory = createFactory()) == NULL) {
return false;
}
return true;
}
template <class T>
void FactoryLoader<T>::closeFactory() {
delete mFactory;
mFactory = NULL;
mLibrary.reset();
}
} // namespace cas
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -0,0 +1,101 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "android.hardware.cas-MediaCasService"
#include <media/cas/CasAPI.h>
#include <media/cas/DescramblerAPI.h>
#include <utils/Log.h>
#include "CasImpl.h"
#include "DescramblerImpl.h"
#include "MediaCasService.h"
namespace aidl {
namespace android {
namespace hardware {
namespace cas {
MediaCasService::MediaCasService()
: mCasLoader("createCasFactory"), mDescramblerLoader("createDescramblerFactory") {}
MediaCasService::~MediaCasService() {}
ScopedAStatus MediaCasService::enumeratePlugins(
vector<AidlCasPluginDescriptor>* aidlCasPluginDescriptors) {
ALOGV("%s", __FUNCTION__);
mCasLoader.enumeratePlugins(aidlCasPluginDescriptors);
return ScopedAStatus::ok();
}
ScopedAStatus MediaCasService::isSystemIdSupported(int32_t CA_system_id, bool* _aidl_return) {
ALOGV("isSystemIdSupported: CA_system_id=%d", CA_system_id);
*_aidl_return = mCasLoader.findFactoryForScheme(CA_system_id);
return ScopedAStatus::ok();
}
ScopedAStatus MediaCasService::createPlugin(int32_t CA_system_id,
const shared_ptr<ICasListener>& listener,
shared_ptr<ICas>* _aidl_return) {
ALOGV("%s: CA_system_id=%d", __FUNCTION__, CA_system_id);
if (listener == NULL) ALOGV("%s: Listener is NULL", __FUNCTION__);
CasFactory* factory;
shared_ptr<SharedLibrary> library;
if (mCasLoader.findFactoryForScheme(CA_system_id, &library, &factory)) {
CasPlugin* plugin = NULL;
shared_ptr<CasImpl> casImpl = ::ndk::SharedRefBase::make<CasImpl>(listener);
if (factory->createPlugin(CA_system_id, casImpl.get(), &CasImpl::CallBackExt, &plugin) ==
OK &&
plugin != NULL) {
casImpl->init(plugin);
*_aidl_return = casImpl;
casImpl->setPluginStatusUpdateCallback();
}
}
return ScopedAStatus::ok();
}
ScopedAStatus MediaCasService::isDescramblerSupported(int32_t CA_system_id, bool* _aidl_return) {
ALOGV("%s: CA_system_id=%d", __FUNCTION__, CA_system_id);
*_aidl_return = mDescramblerLoader.findFactoryForScheme(CA_system_id);
return ScopedAStatus::ok();
}
ScopedAStatus MediaCasService::createDescrambler(int32_t CA_system_id,
shared_ptr<IDescrambler>* _aidl_return) {
ALOGV("%s: CA_system_id=%d", __FUNCTION__, CA_system_id);
DescramblerFactory* factory;
shared_ptr<SharedLibrary> library;
if (mDescramblerLoader.findFactoryForScheme(CA_system_id, &library, &factory)) {
DescramblerPlugin* plugin = NULL;
if (factory->createPlugin(CA_system_id, &plugin) == OK && plugin != NULL) {
*_aidl_return = ::ndk::SharedRefBase::make<DescramblerImpl>(plugin);
}
}
return ScopedAStatus::ok();
}
} // namespace cas
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -0,0 +1,59 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <aidl/android/hardware/cas/BnMediaCasService.h>
#include <media/cas/DescramblerAPI.h>
#include "FactoryLoader.h"
namespace aidl {
namespace android {
namespace hardware {
namespace cas {
using namespace ::android;
using namespace std;
using ndk::ScopedAStatus;
class MediaCasService : public BnMediaCasService {
public:
MediaCasService();
virtual ScopedAStatus enumeratePlugins(
vector<AidlCasPluginDescriptor>* aidlCasPluginDescriptors) override;
virtual ScopedAStatus isSystemIdSupported(int32_t in_CA_system_id, bool* _aidl_return) override;
virtual ScopedAStatus createPlugin(int32_t in_CA_system_id,
const shared_ptr<ICasListener>& in_listener,
shared_ptr<ICas>* _aidl_return) override;
virtual ScopedAStatus isDescramblerSupported(int32_t in_CA_system_id,
bool* _aidl_return) override;
virtual ScopedAStatus createDescrambler(int32_t in_CA_system_id,
shared_ptr<IDescrambler>* _aidl_return) override;
private:
FactoryLoader<CasFactory> mCasLoader;
FactoryLoader<DescramblerFactory> mDescramblerLoader;
virtual ~MediaCasService();
};
} // namespace cas
} // namespace hardware
} // namespace android
} // namespace aidl

3
cas/aidl/default/OWNERS Executable file
View File

@@ -0,0 +1,3 @@
# Bug component: 1344
quxiangfang@google.com
hgchen@google.com

View File

@@ -0,0 +1,61 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "android.hardware.cas-SharedLibrary"
#include "SharedLibrary.h"
#include <dlfcn.h>
#include <utils/Log.h>
namespace aidl {
namespace android {
namespace hardware {
namespace cas {
SharedLibrary::SharedLibrary(const String8& path) {
mLibHandle = dlopen(path.string(), RTLD_NOW);
}
SharedLibrary::~SharedLibrary() {
if (mLibHandle != NULL) {
dlclose(mLibHandle);
mLibHandle = NULL;
}
}
bool SharedLibrary::operator!() const {
return mLibHandle == NULL;
}
void* SharedLibrary::lookup(const char* symbol) const {
if (!mLibHandle) {
return NULL;
}
// Clear last error before we load the symbol again,
// in case the caller didn't retrieve it.
(void)dlerror();
return dlsym(mLibHandle, symbol);
}
const char* SharedLibrary::lastError() const {
const char* error = dlerror();
return error ? error : "No errors or unknown error";
}
} // namespace cas
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -0,0 +1,45 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <android/binder_interface_utils.h>
#include <media/stagefright/foundation/ABase.h>
#include <utils/String8.h>
namespace aidl {
namespace android {
namespace hardware {
namespace cas {
using namespace ::android;
class SharedLibrary : public ndk::SharedRefBase {
public:
explicit SharedLibrary(const String8& path);
~SharedLibrary();
bool operator!() const;
void* lookup(const char* symbol) const;
const char* lastError() const;
private:
void* mLibHandle;
DISALLOW_EVIL_CONSTRUCTORS(SharedLibrary);
};
} // namespace cas
} // namespace hardware
} // namespace android
} // namespace aidl

110
cas/aidl/default/TypeConvert.cpp Executable file
View File

@@ -0,0 +1,110 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "android.hardware.cas-TypeConvert"
#include <aidl/android/hardware/cas/Status.h>
#include <utils/Log.h>
#include "TypeConvert.h"
namespace aidl {
namespace android {
namespace hardware {
namespace cas {
ScopedAStatus toStatus(status_t legacyStatus) {
int status;
switch (legacyStatus) {
case OK:
return ndk::ScopedAStatus::ok();
case ERROR_CAS_NO_LICENSE:
status = Status::ERROR_CAS_NO_LICENSE;
break;
case ERROR_CAS_LICENSE_EXPIRED:
status = Status::ERROR_CAS_LICENSE_EXPIRED;
break;
case ERROR_CAS_SESSION_NOT_OPENED:
status = Status::ERROR_CAS_SESSION_NOT_OPENED;
break;
case ERROR_CAS_CANNOT_HANDLE:
status = Status::ERROR_CAS_CANNOT_HANDLE;
break;
case ERROR_CAS_TAMPER_DETECTED:
status = Status::ERROR_CAS_INVALID_STATE;
break;
case BAD_VALUE:
status = Status::BAD_VALUE;
break;
case ERROR_CAS_NOT_PROVISIONED:
status = Status::ERROR_CAS_NOT_PROVISIONED;
break;
case ERROR_CAS_RESOURCE_BUSY:
status = Status::ERROR_CAS_RESOURCE_BUSY;
break;
case ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION:
status = Status::ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION;
break;
case ERROR_CAS_DEVICE_REVOKED:
status = Status::ERROR_CAS_DEVICE_REVOKED;
break;
case ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED:
status = Status::ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED;
break;
case ERROR_CAS_DECRYPT:
status = Status::ERROR_CAS_DECRYPT;
break;
case ERROR_CAS_NEED_ACTIVATION:
status = Status::ERROR_CAS_NEED_ACTIVATION;
break;
case ERROR_CAS_NEED_PAIRING:
status = Status::ERROR_CAS_NEED_PAIRING;
break;
case ERROR_CAS_NO_CARD:
status = Status::ERROR_CAS_NO_CARD;
break;
case ERROR_CAS_CARD_MUTE:
status = Status::ERROR_CAS_CARD_MUTE;
break;
case ERROR_CAS_CARD_INVALID:
status = Status::ERROR_CAS_CARD_INVALID;
break;
case ERROR_CAS_BLACKOUT:
status = Status::ERROR_CAS_BLACKOUT;
break;
default:
ALOGW("Unable to convert legacy status: %d, defaulting to UNKNOWN", legacyStatus);
status = Status::ERROR_CAS_UNKNOWN;
break;
}
return ScopedAStatus::fromServiceSpecificError(status);
}
String8 sessionIdToString(const std::vector<uint8_t>& sessionId) {
String8 result;
for (auto it = sessionId.begin(); it != sessionId.end(); it++) {
result.appendFormat("%02x ", *it);
}
if (result.isEmpty()) {
result.append("(null)");
}
return result;
}
} // namespace cas
} // namespace hardware
} // namespace android
} // namespace aidl

36
cas/aidl/default/TypeConvert.h Executable file
View File

@@ -0,0 +1,36 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <android/binder_interface_utils.h>
#include <media/stagefright/MediaErrors.h>
#include <utils/String8.h>
namespace aidl {
namespace android {
namespace hardware {
namespace cas {
using namespace ::android;
using ndk::ScopedAStatus;
ScopedAStatus toStatus(status_t legacyStatus);
String8 sessionIdToString(const std::vector<uint8_t>& sessionId);
} // namespace cas
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -0,0 +1,6 @@
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.cas</name>
<fqname>IMediaCasService/default</fqname>
</hal>
</manifest>

View File

@@ -0,0 +1,9 @@
service vendor.cas-default-lazy /vendor/bin/hw/android.hardware.cas-service.example-lazy
interface aidl android.hardware.cas.IMediaCasService/default
class hal
user media
group mediadrm drmrpc
ioprio rt 4
task_profiles ProcessCapacityHigh
oneshot
disabled

View File

@@ -0,0 +1,7 @@
service vendor.cas-default /vendor/bin/hw/android.hardware.cas-service.example
interface aidl android.hardware.cas.IMediaCasService/default
class hal
user media
group mediadrm drmrpc
ioprio rt 4
task_profiles ProcessCapacityHigh

30
cas/aidl/default/fuzzer.cpp Executable file
View File

@@ -0,0 +1,30 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <MediaCasService.h>
#include <fuzzbinder/libbinder_ndk_driver.h>
#include <fuzzer/FuzzedDataProvider.h>
using aidl::android::hardware::cas::MediaCasService;
using android::fuzzService;
using ndk::SharedRefBase;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
auto mediaCasServiceAidl = SharedRefBase::make<MediaCasService>();
fuzzService(mediaCasServiceAidl->asBinder().get(), FuzzedDataProvider(data, size));
return 0;
}

50
cas/aidl/default/service.cpp Executable file
View File

@@ -0,0 +1,50 @@
/*
* Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef LAZY_SERVICE
const bool kLazyService = true;
#define LOG_TAG "android.hardware.cas-service.example-lazy"
#else
const bool kLazyService = false;
#define LOG_TAG "android.hardware.cas-service.example"
#endif
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include "MediaCasService.h"
using aidl::android::hardware::cas::MediaCasService;
int main() {
ABinderProcess_setThreadPoolMaxThreadCount(8);
// Setup hwbinder service
std::shared_ptr<MediaCasService> service = ::ndk::SharedRefBase::make<MediaCasService>();
const std::string instance = std::string() + MediaCasService::descriptor + "/default";
binder_status_t status;
if (kLazyService) {
status = AServiceManager_registerLazyService(service->asBinder().get(), instance.c_str());
} else {
status = AServiceManager_addService(service->asBinder().get(), instance.c_str());
}
LOG_ALWAYS_FATAL_IF(status != STATUS_OK, "Error while registering cas service: %d", status);
ABinderProcess_joinThreadPool();
return 0;
}

View File

@@ -0,0 +1,45 @@
//
// Copyright (C) 2022 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "hardware_interfaces_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["hardware_interfaces_license"],
}
cc_test {
name: "VtsHalCasAidlTargetTest",
defaults: [
"VtsHalTargetTestDefaults",
"use_libaidlvintf_gtest_helper_static",
],
srcs: ["VtsHalCasAidlTargetTest.cpp"],
static_libs: [
"android.hardware.cas-V1-ndk",
"android.hardware.common-V2-ndk",
],
shared_libs: [
"libbinder_ndk",
],
test_suites: [
"general-tests",
"vts",
],
disable_framework: true,
}

View File

@@ -0,0 +1,3 @@
# Bug component: 1344
quxiangfang@google.com
hgchen@google.com

View File

@@ -0,0 +1,809 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "mediacas_aidl_hal_test"
#include <aidl/Gtest.h>
#include <aidl/Vintf.h>
#include <aidl/android/hardware/cas/BnCasListener.h>
#include <aidl/android/hardware/cas/IMediaCasService.h>
#include <aidl/android/hardware/cas/Status.h>
#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include <binder/ParcelFileDescriptor.h>
#include <cutils/ashmem.h>
#include <utils/Condition.h>
#include <utils/Mutex.h>
#define CLEAR_KEY_SYSTEM_ID 0xF6D8
#define INVALID_SYSTEM_ID 0
#define WAIT_TIMEOUT 3000000000
#define PROVISION_STR \
"{ " \
" \"id\": 21140844, " \
" \"name\": \"Test Title\", " \
" \"lowercase_organization_name\": \"Android\", " \
" \"asset_key\": { " \
" \"encryption_key\": \"nezAr3CHFrmBR9R8Tedotw==\" " \
" }, " \
" \"cas_type\": 1, " \
" \"track_types\": [ ] " \
"} "
using aidl::android::hardware::common::Ashmem;
using android::Mutex;
using namespace aidl::android::hardware::cas;
using namespace ndk;
using namespace std;
using namespace testing;
const uint8_t kEcmBinaryBuffer[] = {
0x00, 0x00, 0x01, 0xf0, 0x00, 0x50, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x46, 0x00,
0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x27, 0x10, 0x02, 0x00,
0x01, 0x77, 0x01, 0x42, 0x95, 0x6c, 0x0e, 0xe3, 0x91, 0xbc, 0xfd, 0x05, 0xb1, 0x60, 0x4f,
0x17, 0x82, 0xa4, 0x86, 0x9b, 0x23, 0x56, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
0x27, 0x10, 0x02, 0x00, 0x01, 0x77, 0x01, 0x42, 0x95, 0x6c, 0xd7, 0x43, 0x62, 0xf8, 0x1c,
0x62, 0x19, 0x05, 0xc7, 0x3a, 0x42, 0xcd, 0xfd, 0xd9, 0x13, 0x48,
};
const SubSample kSubSamples[] = {{162, 0}, {0, 184}, {0, 184}};
const uint8_t kInBinaryBuffer[] = {
0x00, 0x00, 0x00, 0x01, 0x09, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0xc0, 0x1e, 0xdb,
0x01, 0x40, 0x16, 0xec, 0x04, 0x40, 0x00, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x0f, 0x03,
0xc5, 0x8b, 0xb8, 0x00, 0x00, 0x00, 0x01, 0x68, 0xca, 0x8c, 0xb2, 0x00, 0x00, 0x01, 0x06,
0x05, 0xff, 0xff, 0x70, 0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8,
0x20, 0xd9, 0x23, 0xee, 0xef, 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x72,
0x65, 0x20, 0x31, 0x34, 0x32, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34, 0x2f, 0x4d,
0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x63,
0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30,
0x33, 0x2d, 0x32, 0x30, 0x31, 0x34, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, 0x2e, 0x6f,
0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x6e, 0x45, 0x21,
0x82, 0x38, 0xf0, 0x9d, 0x7d, 0x96, 0xe6, 0x94, 0xae, 0xe2, 0x87, 0x8f, 0x04, 0x49, 0xe5,
0xf6, 0x8c, 0x8b, 0x9a, 0x10, 0x18, 0xba, 0x94, 0xe9, 0x22, 0x31, 0x04, 0x7e, 0x60, 0x5b,
0xc4, 0x24, 0x00, 0x90, 0x62, 0x0d, 0xdc, 0x85, 0x74, 0x75, 0x78, 0xd0, 0x14, 0x08, 0xcb,
0x02, 0x1d, 0x7d, 0x9d, 0x34, 0xe8, 0x81, 0xb9, 0xf7, 0x09, 0x28, 0x79, 0x29, 0x8d, 0xe3,
0x14, 0xed, 0x5f, 0xca, 0xaf, 0xf4, 0x1c, 0x49, 0x15, 0xe1, 0x80, 0x29, 0x61, 0x76, 0x80,
0x43, 0xf8, 0x58, 0x53, 0x40, 0xd7, 0x31, 0x6d, 0x61, 0x81, 0x41, 0xe9, 0x77, 0x9f, 0x9c,
0xe1, 0x6d, 0xf2, 0xee, 0xd9, 0xc8, 0x67, 0xd2, 0x5f, 0x48, 0x73, 0xe3, 0x5c, 0xcd, 0xa7,
0x45, 0x58, 0xbb, 0xdd, 0x28, 0x1d, 0x68, 0xfc, 0xb4, 0xc6, 0xf6, 0x92, 0xf6, 0x30, 0x03,
0xaa, 0xe4, 0x32, 0xf6, 0x34, 0x51, 0x4b, 0x0f, 0x8c, 0xf9, 0xac, 0x98, 0x22, 0xfb, 0x49,
0xc8, 0xbf, 0xca, 0x8c, 0x80, 0x86, 0x5d, 0xd7, 0xa4, 0x52, 0xb1, 0xd9, 0xa6, 0x04, 0x4e,
0xb3, 0x2d, 0x1f, 0xb8, 0x35, 0xcc, 0x45, 0x6d, 0x9c, 0x20, 0xa7, 0xa4, 0x34, 0x59, 0x72,
0xe3, 0xae, 0xba, 0x49, 0xde, 0xd1, 0xaa, 0xee, 0x3d, 0x77, 0xfc, 0x5d, 0xc6, 0x1f, 0x9d,
0xac, 0xc2, 0x15, 0x66, 0xb8, 0xe1, 0x54, 0x4e, 0x74, 0x93, 0xdb, 0x9a, 0x24, 0x15, 0x6e,
0x20, 0xa3, 0x67, 0x3e, 0x5a, 0x24, 0x41, 0x5e, 0xb0, 0xe6, 0x35, 0x87, 0x1b, 0xc8, 0x7a,
0xf9, 0x77, 0x65, 0xe0, 0x01, 0xf2, 0x4c, 0xe4, 0x2b, 0xa9, 0x64, 0x96, 0x96, 0x0b, 0x46,
0xca, 0xea, 0x79, 0x0e, 0x78, 0xa3, 0x5f, 0x43, 0xfc, 0x47, 0x6a, 0x12, 0xfa, 0xc4, 0x33,
0x0e, 0x88, 0x1c, 0x19, 0x3a, 0x00, 0xc3, 0x4e, 0xb5, 0xd8, 0xfa, 0x8e, 0xf1, 0xbc, 0x3d,
0xb2, 0x7e, 0x50, 0x8d, 0x67, 0xc3, 0x6b, 0xed, 0xe2, 0xea, 0xa6, 0x1f, 0x25, 0x24, 0x7c,
0x94, 0x74, 0x50, 0x49, 0xe3, 0xc6, 0x58, 0x2e, 0xfd, 0x28, 0xb4, 0xc6, 0x73, 0xb1, 0x53,
0x74, 0x27, 0x94, 0x5c, 0xdf, 0x69, 0xb7, 0xa1, 0xd7, 0xf5, 0xd3, 0x8a, 0x2c, 0x2d, 0xb4,
0x5e, 0x8a, 0x16, 0x14, 0x54, 0x64, 0x6e, 0x00, 0x6b, 0x11, 0x59, 0x8a, 0x63, 0x38, 0x80,
0x76, 0xc3, 0xd5, 0x59, 0xf7, 0x3f, 0xd2, 0xfa, 0xa5, 0xca, 0x82, 0xff, 0x4a, 0x62, 0xf0,
0xe3, 0x42, 0xf9, 0x3b, 0x38, 0x27, 0x8a, 0x89, 0xaa, 0x50, 0x55, 0x4b, 0x29, 0xf1, 0x46,
0x7c, 0x75, 0xef, 0x65, 0xaf, 0x9b, 0x0d, 0x6d, 0xda, 0x25, 0x94, 0x14, 0xc1, 0x1b, 0xf0,
0xc5, 0x4c, 0x24, 0x0e, 0x65,
};
const uint8_t kOutRefBinaryBuffer[] = {
0x00, 0x00, 0x00, 0x01, 0x09, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0xc0, 0x1e, 0xdb,
0x01, 0x40, 0x16, 0xec, 0x04, 0x40, 0x00, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x0f, 0x03,
0xc5, 0x8b, 0xb8, 0x00, 0x00, 0x00, 0x01, 0x68, 0xca, 0x8c, 0xb2, 0x00, 0x00, 0x01, 0x06,
0x05, 0xff, 0xff, 0x70, 0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8,
0x20, 0xd9, 0x23, 0xee, 0xef, 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x72,
0x65, 0x20, 0x31, 0x34, 0x32, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34, 0x2f, 0x4d,
0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x63,
0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30,
0x33, 0x2d, 0x32, 0x30, 0x31, 0x34, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, 0x2e, 0x6f,
0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x2d, 0x20,
0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x20, 0x63, 0x61, 0x62, 0x61, 0x63, 0x3d,
0x30, 0x20, 0x72, 0x65, 0x66, 0x3d, 0x32, 0x20, 0x64, 0x65, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
0x3d, 0x31, 0x3a, 0x30, 0x3a, 0x30, 0x20, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x65, 0x3d,
0x30, 0x78, 0x31, 0x3a, 0x30, 0x78, 0x31, 0x31, 0x31, 0x20, 0x6d, 0x65, 0x3d, 0x68, 0x65,
0x78, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x65, 0x3d, 0x37, 0x20, 0x70, 0x73, 0x79, 0x3d, 0x31,
0x20, 0x70, 0x73, 0x79, 0x5f, 0x72, 0x64, 0x3d, 0x31, 0x2e, 0x30, 0x30, 0x3a, 0x30, 0x2e,
0x30, 0x30, 0x20, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x66, 0x3d, 0x31, 0x20,
0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x3d, 0x31, 0x36, 0x20, 0x63, 0x68, 0x72,
0x6f, 0x6d, 0x61, 0x5f, 0x6d, 0x65, 0x3d, 0x31, 0x20, 0x74, 0x72, 0x65, 0x6c, 0x6c, 0x69,
0x73, 0x3d, 0x31, 0x20, 0x38, 0x78, 0x38, 0x64, 0x63, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x71,
0x6d, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x61, 0x64, 0x7a, 0x6f, 0x6e, 0x65, 0x3d, 0x32, 0x31,
0x2c, 0x31, 0x31, 0x20, 0x66, 0x61, 0x73, 0x74, 0x5f, 0x70, 0x73, 0x6b, 0x69, 0x70, 0x3d,
0x31, 0x20, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x61, 0x5f, 0x71, 0x70, 0x5f, 0x6f, 0x66, 0x66,
0x73, 0x65, 0x74, 0x3d, 0x2d, 0x32, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d,
0x36, 0x30, 0x20, 0x6c, 0x6f, 0x6f, 0x6b, 0x61, 0x68, 0x65, 0x61, 0x64, 0x5f, 0x74, 0x68,
0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x35, 0x20, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x64, 0x5f,
0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x30, 0x20, 0x6e, 0x72, 0x3d, 0x30, 0x20,
0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x20, 0x69, 0x6e, 0x74, 0x65,
0x72, 0x6c, 0x61, 0x63, 0x65, 0x64, 0x3d, 0x30, 0x20, 0x62, 0x6c, 0x75, 0x72, 0x61, 0x79,
0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74,
0x72, 0x61, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x72, 0x61, 0x3d, 0x30, 0x20,
0x62, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x3d, 0x30, 0x20, 0x77, 0x65, 0x69, 0x67, 0x68,
0x74, 0x70, 0x3d, 0x30, 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x3d, 0x32, 0x35, 0x30,
0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x3d, 0x32, 0x35, 0x20,
0x73, 0x63, 0x65, 0x6e, 0x65,
};
class MediaCasListener : public BnCasListener {
public:
virtual ScopedAStatus onEvent(int32_t event, int32_t arg,
const vector<uint8_t>& data) override {
Mutex::Autolock autoLock(mMsgLock);
mEvent = event;
mEventArg = arg;
mEventData = data;
mEventReceived = true;
mMsgCondition.signal();
return ScopedAStatus::ok();
}
virtual ScopedAStatus onSessionEvent(const vector<uint8_t>& sessionId, int32_t event,
int32_t arg, const vector<uint8_t>& data) override {
Mutex::Autolock autoLock(mMsgLock);
mSessionId = sessionId;
mEvent = event;
mEventArg = arg;
mEventData = data;
mEventReceived = true;
mMsgCondition.signal();
return ScopedAStatus::ok();
}
virtual ScopedAStatus onStatusUpdate(StatusEvent event, int32_t arg) override {
Mutex::Autolock autoLock(mMsgLock);
mStatusEvent = event;
mEventArg = arg;
mEventReceived = true;
mMsgCondition.signal();
return ScopedAStatus::ok();
}
void testEventEcho(shared_ptr<ICas>& mediaCas, int32_t& event, int32_t& eventArg,
vector<uint8_t>& eventData);
void testSessionEventEcho(shared_ptr<ICas>& mediaCas, const vector<uint8_t>& sessionId,
int32_t& event, int32_t& eventArg, vector<uint8_t>& eventData);
void testStatusUpdate(shared_ptr<ICas>& mediaCas, vector<uint8_t>* sessionId,
SessionIntent intent, ScramblingMode mode);
private:
int32_t mEvent = -1;
int32_t mEventArg = -1;
StatusEvent mStatusEvent;
bool mEventReceived = false;
vector<uint8_t> mEventData;
vector<uint8_t> mSessionId;
Mutex mMsgLock;
android::Condition mMsgCondition;
};
void MediaCasListener::testEventEcho(shared_ptr<ICas>& mediaCas, int32_t& event, int32_t& eventArg,
vector<uint8_t>& eventData) {
mEventReceived = false;
auto returnStatus = mediaCas->sendEvent(event, eventArg, eventData);
EXPECT_TRUE(returnStatus.isOk());
Mutex::Autolock autoLock(mMsgLock);
while (!mEventReceived) {
if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
ADD_FAILURE() << "event not received within timeout";
return;
}
}
EXPECT_EQ(mEvent, event);
EXPECT_EQ(mEventArg, eventArg);
EXPECT_TRUE(mEventData == eventData);
}
void MediaCasListener::testSessionEventEcho(shared_ptr<ICas>& mediaCas,
const vector<uint8_t>& sessionId, int32_t& event,
int32_t& eventArg, vector<uint8_t>& eventData) {
mEventReceived = false;
EXPECT_TRUE(mediaCas->sendSessionEvent(sessionId, event, eventArg, eventData).isOk());
Mutex::Autolock autoLock(mMsgLock);
while (!mEventReceived) {
if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
ADD_FAILURE() << "event not received within timeout";
return;
}
}
EXPECT_TRUE(mSessionId == sessionId);
EXPECT_EQ(mEvent, event);
EXPECT_EQ(mEventArg, eventArg);
EXPECT_TRUE(mEventData == eventData);
}
void MediaCasListener::testStatusUpdate(shared_ptr<ICas>& mediaCas, vector<uint8_t>* sessionId,
SessionIntent intent, ScramblingMode mode) {
mEventReceived = false;
EXPECT_TRUE(mediaCas->openSession(intent, mode, sessionId).isOk());
Mutex::Autolock autoLock(mMsgLock);
while (!mEventReceived) {
if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
ADD_FAILURE() << "event not received within timeout";
return;
}
}
EXPECT_EQ(mStatusEvent, static_cast<StatusEvent>(intent));
EXPECT_EQ(mEventArg, static_cast<int32_t>(mode));
}
class MediaCasAidlTest : public testing::TestWithParam<string> {
public:
virtual void SetUp() override {
if (AServiceManager_isDeclared(GetParam().c_str())) {
SpAIBinder binder(AServiceManager_waitForService(GetParam().c_str()));
mService = IMediaCasService::fromBinder(binder);
} else {
mService = nullptr;
}
ASSERT_NE(mService, nullptr);
}
shared_ptr<IMediaCasService> mService = nullptr;
protected:
static void description(const string& description) {
RecordProperty("description", description);
}
shared_ptr<ICas> mMediaCas;
shared_ptr<IDescrambler> mDescrambler;
shared_ptr<MediaCasListener> mCasListener;
typedef struct _OobInputTestParams {
const SubSample* subSamples;
int32_t numSubSamples;
int64_t imemSizeActual;
int64_t imemOffset;
int64_t imemSize;
int64_t srcOffset;
int64_t dstOffset;
} OobInputTestParams;
AssertionResult createCasPlugin(int32_t caSystemId);
AssertionResult openCasSession(vector<uint8_t>* sessionId, SessionIntent intent,
ScramblingMode mode);
AssertionResult descrambleTestInputBuffer(const shared_ptr<IDescrambler>& descrambler,
ScopedAStatus& descrambleStatus, uint8_t*& inMemory);
AssertionResult descrambleTestOobInput(const shared_ptr<IDescrambler>& descrambler,
ScopedAStatus& descrambleStatus,
const OobInputTestParams& params);
};
AssertionResult MediaCasAidlTest::createCasPlugin(int32_t caSystemId) {
bool isSystemIdSupported;
auto status = mService->isSystemIdSupported(caSystemId, &isSystemIdSupported);
bool skipDescrambler = false;
if (!status.isOk() || !isSystemIdSupported) {
return AssertionFailure();
}
bool isDescramblerSupported;
status = mService->isDescramblerSupported(caSystemId, &isDescramblerSupported);
if (!status.isOk() || !isDescramblerSupported) {
ALOGI("Skip Descrambler test since it's not required in cas.");
mDescrambler = nullptr;
skipDescrambler = true;
}
mCasListener = SharedRefBase::make<MediaCasListener>();
status = mService->createPlugin(caSystemId, mCasListener, &mMediaCas);
if (!status.isOk()) {
return AssertionFailure();
}
if (mMediaCas == nullptr) {
return AssertionFailure();
}
if (skipDescrambler) {
return AssertionSuccess();
}
status = mService->createDescrambler(caSystemId, &mDescrambler);
if (!status.isOk()) {
return AssertionFailure();
}
return AssertionResult(mDescrambler != nullptr);
}
AssertionResult MediaCasAidlTest::openCasSession(vector<uint8_t>* sessionId, SessionIntent intent,
ScramblingMode mode) {
return AssertionResult(mMediaCas->openSession(intent, mode, sessionId).isOk());
}
AssertionResult MediaCasAidlTest::descrambleTestInputBuffer(
const shared_ptr<IDescrambler>& descrambler, ScopedAStatus& descrambleStatus,
uint8_t*& sharedMemory) {
vector<SubSample> subSample(kSubSamples,
kSubSamples + (sizeof(kSubSamples) / sizeof(SubSample)));
int size = sizeof(kInBinaryBuffer);
auto fd = ashmem_create_region("vts-cas", size);
if (fd < 0) {
ALOGE("ashmem_create_region failed");
return AssertionFailure();
}
sharedMemory =
static_cast<uint8_t*>(mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
if (sharedMemory == reinterpret_cast<uint8_t*>(MAP_FAILED)) {
ALOGE("mmap failed");
return AssertionFailure();
}
memcpy(sharedMemory, kInBinaryBuffer, size);
auto dupFd = dup(fd);
SharedBuffer srcBuffer = {.heapBase.fd = ScopedFileDescriptor(std::move(fd)),
.heapBase.size = size,
.offset = 0,
.size = size};
SharedBuffer dupBuffer = {.heapBase.fd = ScopedFileDescriptor(dupFd),
.heapBase.size = size,
.offset = 0,
.size = size};
DestinationBuffer dstBuffer;
dstBuffer.set<DestinationBuffer::nonsecureMemory>(std::move(dupBuffer));
int32_t outBytes;
descrambleStatus = descrambler->descramble(ScramblingControl::EVENKEY /*2*/, subSample,
srcBuffer, 0, dstBuffer, 0, &outBytes);
if (!descrambleStatus.isOk()) {
ALOGI("descramble failed, status=%d, outBytes=%u, error=%s", descrambleStatus.getStatus(),
outBytes, descrambleStatus.getDescription().c_str());
}
return AssertionResult(descrambleStatus.isOk());
}
AssertionResult MediaCasAidlTest::descrambleTestOobInput(
const shared_ptr<IDescrambler>& descrambler, ScopedAStatus& descrambleStatus,
const OobInputTestParams& params) {
vector<SubSample> subSample(params.subSamples, params.subSamples + params.numSubSamples);
auto fd = ashmem_create_region("vts-cas", params.imemSizeActual);
if (fd < 0) {
ALOGE("ashmem_create_region failed");
return AssertionFailure();
}
auto dupFd = dup(fd);
SharedBuffer srcBuffer = {.heapBase.fd = ScopedFileDescriptor(std::move(fd)),
.heapBase.size = params.imemSizeActual,
.offset = params.imemOffset,
.size = params.imemSize};
SharedBuffer dupBuffer = {.heapBase.fd = ScopedFileDescriptor(dupFd),
.heapBase.size = params.imemSizeActual,
.offset = params.imemOffset,
.size = params.imemSize};
DestinationBuffer dstBuffer;
dstBuffer.set<DestinationBuffer::nonsecureMemory>(std::move(dupBuffer));
int32_t outBytes;
descrambleStatus =
descrambler->descramble(ScramblingControl::EVENKEY /*2*/, subSample, srcBuffer,
params.srcOffset, dstBuffer, params.dstOffset, &outBytes);
if (!descrambleStatus.isOk()) {
ALOGI("descramble failed, status=%d, outBytes=%u, error=%s", descrambleStatus.getStatus(),
outBytes, descrambleStatus.getDescription().c_str());
}
return AssertionResult(descrambleStatus.isOk());
}
TEST_P(MediaCasAidlTest, EnumeratePlugins) {
description("Test enumerate plugins");
vector<AidlCasPluginDescriptor> descriptors;
EXPECT_TRUE(mService->enumeratePlugins(&descriptors).isOk());
if (descriptors.size() == 0) {
ALOGW("[ WARN ] enumeratePlugins list empty");
return;
}
for (size_t i = 0; i < descriptors.size(); i++) {
int32_t caSystemId = descriptors[i].caSystemId;
ASSERT_TRUE(createCasPlugin(caSystemId));
}
}
TEST_P(MediaCasAidlTest, TestInvalidSystemIdFails) {
description("Test failure for invalid system ID");
bool isSystemIdSupported;
auto status = mService->isSystemIdSupported(INVALID_SYSTEM_ID, &isSystemIdSupported);
EXPECT_TRUE(status.isOk());
ASSERT_FALSE(isSystemIdSupported);
bool isDescramblerSupported;
status = mService->isDescramblerSupported(INVALID_SYSTEM_ID, &isDescramblerSupported);
EXPECT_TRUE(status.isOk());
ASSERT_FALSE(isDescramblerSupported);
shared_ptr<ICas> mediaCas;
shared_ptr<MediaCasListener> casListener = SharedRefBase::make<MediaCasListener>();
status = mService->createPlugin(INVALID_SYSTEM_ID, casListener, &mediaCas);
ASSERT_TRUE(status.isOk());
EXPECT_EQ(mediaCas, nullptr);
shared_ptr<IDescrambler> descrambler;
status = mService->createDescrambler(INVALID_SYSTEM_ID, &descrambler);
ASSERT_TRUE(status.isOk());
EXPECT_EQ(descrambler, nullptr);
}
TEST_P(MediaCasAidlTest, TestClearKeyPluginInstalled) {
description("Test if ClearKey plugin is installed");
vector<AidlCasPluginDescriptor> descriptors;
EXPECT_TRUE(mService->enumeratePlugins(&descriptors).isOk());
if (descriptors.size() == 0) {
ALOGW("[ WARN ] enumeratePlugins list empty");
}
for (size_t i = 0; i < descriptors.size(); i++) {
int32_t caSystemId = descriptors[i].caSystemId;
if (CLEAR_KEY_SYSTEM_ID == caSystemId) {
return;
}
}
ADD_FAILURE() << "ClearKey plugin not installed";
}
TEST_P(MediaCasAidlTest, TestClearKeySessionClosedAfterRelease) {
description("Test that all sessions are closed after a MediaCas object is released");
ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
EXPECT_TRUE(mMediaCas->provision(PROVISION_STR).isOk());
SessionIntent intent = SessionIntent::LIVE;
ScramblingMode mode = ScramblingMode::DVB_CSA1;
vector<uint8_t> sessionId;
ASSERT_TRUE(openCasSession(&sessionId, intent, mode));
vector<uint8_t> streamSessionId;
ASSERT_TRUE(openCasSession(&streamSessionId, intent, mode));
EXPECT_TRUE(mMediaCas->release().isOk());
if (mDescrambler != nullptr) {
auto status = mDescrambler->setMediaCasSession(sessionId);
EXPECT_FALSE(status.isOk());
EXPECT_EQ(Status::ERROR_CAS_SESSION_NOT_OPENED, status.getServiceSpecificError());
status = mDescrambler->setMediaCasSession(streamSessionId);
EXPECT_FALSE(status.isOk());
EXPECT_EQ(Status::ERROR_CAS_SESSION_NOT_OPENED, status.getServiceSpecificError());
}
}
TEST_P(MediaCasAidlTest, TestClearKeyErrors) {
description("Test that invalid call sequences fail with expected error codes");
ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
/*
* Test MediaCas error codes
*/
// Provision should fail with an invalid asset string
auto returnStatus = mMediaCas->provision("invalid asset string");
EXPECT_FALSE(returnStatus.isOk());
EXPECT_EQ(Status::ERROR_CAS_NO_LICENSE, returnStatus.getServiceSpecificError());
SessionIntent intent = SessionIntent::LIVE;
ScramblingMode mode = ScramblingMode::DVB_CSA1;
// Open a session, then close it so that it should become invalid
vector<uint8_t> invalidSessionId;
ASSERT_TRUE(openCasSession(&invalidSessionId, intent, mode));
EXPECT_TRUE(mMediaCas->closeSession(invalidSessionId).isOk());
// processEcm should fail with an invalid session id
vector<uint8_t> ecm(kEcmBinaryBuffer, kEcmBinaryBuffer + sizeof(kEcmBinaryBuffer));
returnStatus = mMediaCas->processEcm(invalidSessionId, ecm);
EXPECT_FALSE(returnStatus.isOk());
EXPECT_EQ(Status::ERROR_CAS_SESSION_NOT_OPENED, returnStatus.getServiceSpecificError());
vector<uint8_t> sessionId;
ASSERT_TRUE(openCasSession(&sessionId, intent, mode));
// processEcm should fail without provisioning
returnStatus = mMediaCas->processEcm(sessionId, ecm);
EXPECT_FALSE(returnStatus.isOk());
EXPECT_EQ(Status::ERROR_CAS_NOT_PROVISIONED, returnStatus.getServiceSpecificError());
EXPECT_TRUE(mMediaCas->provision(PROVISION_STR).isOk());
// processEcm should fail with ecm with bad descriptor count
ecm[17] = 0x03; // change the descriptor count field to 3 (invalid)
returnStatus = mMediaCas->processEcm(sessionId, ecm);
EXPECT_FALSE(returnStatus.isOk());
EXPECT_EQ(Status::ERROR_CAS_UNKNOWN, returnStatus.getServiceSpecificError());
// processEcm should fail with ecm buffer that's too short
ecm.resize(8);
returnStatus = mMediaCas->processEcm(sessionId, ecm);
EXPECT_FALSE(returnStatus.isOk());
EXPECT_EQ(Status::BAD_VALUE, returnStatus.getServiceSpecificError());
if (mDescrambler != nullptr) {
/*
* Test MediaDescrambler error codes
*/
// setMediaCasSession should fail with an invalid session id
returnStatus = mDescrambler->setMediaCasSession(invalidSessionId);
EXPECT_FALSE(returnStatus.isOk());
EXPECT_EQ(Status::ERROR_CAS_SESSION_NOT_OPENED, returnStatus.getServiceSpecificError());
// descramble should fail without a valid session
ScopedAStatus descrambleStatus = ScopedAStatus::ok();
uint8_t* sharedBuffer = nullptr;
ASSERT_FALSE(descrambleTestInputBuffer(mDescrambler, descrambleStatus, sharedBuffer));
EXPECT_EQ(Status::ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED,
descrambleStatus.getServiceSpecificError());
// Now set a valid session, should still fail because no valid ecm is processed
EXPECT_TRUE(mDescrambler->setMediaCasSession(sessionId).isOk());
ASSERT_FALSE(descrambleTestInputBuffer(mDescrambler, descrambleStatus, sharedBuffer));
EXPECT_EQ(Status::ERROR_CAS_DECRYPT, descrambleStatus.getServiceSpecificError());
// Verify that requiresSecureDecoderComponent handles empty mime
bool requiresSecureDecoderComponent = true;
EXPECT_TRUE(
mDescrambler->requiresSecureDecoderComponent("", &requiresSecureDecoderComponent)
.isOk());
EXPECT_FALSE(requiresSecureDecoderComponent);
// Verify that requiresSecureDecoderComponent handles invalid mime
requiresSecureDecoderComponent = true;
EXPECT_TRUE(
mDescrambler->requiresSecureDecoderComponent("bad", &requiresSecureDecoderComponent)
.isOk());
EXPECT_FALSE(requiresSecureDecoderComponent);
}
}
TEST_P(MediaCasAidlTest, TestClearKeyApisWithSession) {
description("Test that valid call sequences with SessionEvent send and receive");
ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
EXPECT_TRUE(mMediaCas->provision(PROVISION_STR).isOk());
vector<uint8_t> pvtData;
pvtData.resize(256);
EXPECT_TRUE(mMediaCas->setPrivateData(pvtData).isOk());
SessionIntent intent = SessionIntent::LIVE;
ScramblingMode mode = ScramblingMode::DVB_CSA1;
vector<uint8_t> sessionId;
ASSERT_TRUE(openCasSession(&sessionId, intent, mode));
EXPECT_TRUE(mMediaCas->setSessionPrivateData(sessionId, pvtData).isOk());
vector<uint8_t> streamSessionId;
ASSERT_TRUE(openCasSession(&streamSessionId, intent, mode));
EXPECT_TRUE(mMediaCas->setSessionPrivateData(streamSessionId, pvtData).isOk());
if (mDescrambler != nullptr) {
EXPECT_TRUE(mDescrambler->setMediaCasSession(sessionId).isOk());
EXPECT_TRUE(mDescrambler->setMediaCasSession(streamSessionId).isOk());
}
vector<uint8_t> nullPtrVector(0);
EXPECT_TRUE(mMediaCas->refreshEntitlements(3, nullPtrVector).isOk());
vector<uint8_t> refreshData{0, 1, 2, 3};
EXPECT_TRUE(mMediaCas->refreshEntitlements(10, refreshData).isOk());
int32_t eventID = 1;
int32_t eventArg = 2;
mCasListener->testEventEcho(mMediaCas, eventID, eventArg, nullPtrVector);
mCasListener->testSessionEventEcho(mMediaCas, sessionId, eventID, eventArg, nullPtrVector);
eventID = 3;
eventArg = 4;
vector<uint8_t> eventData{'e', 'v', 'e', 'n', 't', 'd', 'a', 't', 'a'};
mCasListener->testEventEcho(mMediaCas, eventID, eventArg, eventData);
mCasListener->testSessionEventEcho(mMediaCas, sessionId, eventID, eventArg, eventData);
mCasListener->testStatusUpdate(mMediaCas, &sessionId, intent, mode);
vector<uint8_t> clearKeyEmmData{'c', 'l', 'e', 'a', 'r', 'k', 'e', 'y', 'e', 'm', 'm'};
EXPECT_TRUE(mMediaCas->processEmm(clearKeyEmmData).isOk());
vector<uint8_t> ecm(kEcmBinaryBuffer, kEcmBinaryBuffer + sizeof(kEcmBinaryBuffer));
EXPECT_TRUE(mMediaCas->processEcm(sessionId, ecm).isOk());
EXPECT_TRUE(mMediaCas->processEcm(streamSessionId, ecm).isOk());
if (mDescrambler != nullptr) {
bool requiresSecureDecoderComponent = true;
EXPECT_TRUE(mDescrambler
->requiresSecureDecoderComponent("video/avc",
&requiresSecureDecoderComponent)
.isOk());
EXPECT_FALSE(requiresSecureDecoderComponent);
ScopedAStatus descrambleStatus = ScopedAStatus::ok();
uint8_t* sharedBuffer = nullptr;
ASSERT_TRUE(descrambleTestInputBuffer(mDescrambler, descrambleStatus, sharedBuffer));
int compareResult =
memcmp(static_cast<const void*>(sharedBuffer),
static_cast<const void*>(kOutRefBinaryBuffer), sizeof(kOutRefBinaryBuffer));
EXPECT_EQ(0, compareResult);
EXPECT_TRUE(mDescrambler->release().isOk());
}
EXPECT_TRUE(mMediaCas->release().isOk());
}
TEST_P(MediaCasAidlTest, TestClearKeyOobFails) {
description("Test that oob descramble request fails with expected error");
ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
EXPECT_TRUE(mMediaCas->provision(PROVISION_STR).isOk());
SessionIntent intent = SessionIntent::LIVE;
ScramblingMode mode = ScramblingMode::DVB_CSA1;
vector<uint8_t> sessionId;
ASSERT_TRUE(openCasSession(&sessionId, intent, mode));
if (mDescrambler != nullptr) {
EXPECT_TRUE(mDescrambler->setMediaCasSession(sessionId).isOk());
}
vector<uint8_t> ecm(kEcmBinaryBuffer, kEcmBinaryBuffer + sizeof(kEcmBinaryBuffer));
EXPECT_TRUE(mMediaCas->processEcm(sessionId, ecm).isOk());
if (mDescrambler != nullptr) {
ScopedAStatus descrambleStatus = ScopedAStatus::ok();
// test invalid src buffer offset
ASSERT_FALSE(
descrambleTestOobInput(mDescrambler, descrambleStatus,
{.subSamples = kSubSamples,
.numSubSamples = sizeof(kSubSamples) / sizeof(SubSample),
.imemSizeActual = sizeof(kInBinaryBuffer),
.imemOffset = 0xcccccc,
.imemSize = sizeof(kInBinaryBuffer),
.srcOffset = 0,
.dstOffset = 0}));
EXPECT_EQ(Status::BAD_VALUE, descrambleStatus.getServiceSpecificError());
// test invalid src buffer size
ASSERT_FALSE(
descrambleTestOobInput(mDescrambler, descrambleStatus,
{.subSamples = kSubSamples,
.numSubSamples = sizeof(kSubSamples) / sizeof(SubSample),
.imemSizeActual = sizeof(kInBinaryBuffer),
.imemOffset = 0,
.imemSize = 0xcccccc,
.srcOffset = 0,
.dstOffset = 0}));
EXPECT_EQ(Status::BAD_VALUE, descrambleStatus.getServiceSpecificError());
// test invalid src buffer size
ASSERT_FALSE(
descrambleTestOobInput(mDescrambler, descrambleStatus,
{.subSamples = kSubSamples,
.numSubSamples = sizeof(kSubSamples) / sizeof(SubSample),
.imemSizeActual = sizeof(kInBinaryBuffer),
.imemOffset = 1,
.imemSize = -1,
.srcOffset = 0,
.dstOffset = 0}));
EXPECT_EQ(Status::BAD_VALUE, descrambleStatus.getServiceSpecificError());
// test invalid srcOffset
ASSERT_FALSE(
descrambleTestOobInput(mDescrambler, descrambleStatus,
{.subSamples = kSubSamples,
.numSubSamples = sizeof(kSubSamples) / sizeof(SubSample),
.imemSizeActual = sizeof(kInBinaryBuffer),
.imemOffset = 0,
.imemSize = sizeof(kInBinaryBuffer),
.srcOffset = 0xcccccc,
.dstOffset = 0}));
EXPECT_EQ(Status::BAD_VALUE, descrambleStatus.getServiceSpecificError());
// test invalid dstOffset
ASSERT_FALSE(
descrambleTestOobInput(mDescrambler, descrambleStatus,
{.subSamples = kSubSamples,
.numSubSamples = sizeof(kSubSamples) / sizeof(SubSample),
.imemSizeActual = sizeof(kInBinaryBuffer),
.imemOffset = 0,
.imemSize = sizeof(kInBinaryBuffer),
.srcOffset = 0,
.dstOffset = 0xcccccc}));
EXPECT_EQ(Status::BAD_VALUE, descrambleStatus.getServiceSpecificError());
// test detection of oob subsample sizes
const SubSample invalidSubSamples1[] = {{162, 0}, {0, 184}, {0, 0xdddddd}};
ASSERT_FALSE(descrambleTestOobInput(
mDescrambler, descrambleStatus,
{.subSamples = invalidSubSamples1,
.numSubSamples = sizeof(invalidSubSamples1) / sizeof(SubSample),
.imemSizeActual = sizeof(kInBinaryBuffer),
.imemOffset = 0,
.imemSize = sizeof(kInBinaryBuffer),
.srcOffset = 0,
.dstOffset = 0}));
EXPECT_EQ(Status::BAD_VALUE, descrambleStatus.getServiceSpecificError());
// test detection of overflowing subsample sizes
const SubSample invalidSubSamples2[] = {{162, 0}, {0, 184}, {2, -1}};
ASSERT_FALSE(descrambleTestOobInput(
mDescrambler, descrambleStatus,
{.subSamples = invalidSubSamples2,
.numSubSamples = sizeof(invalidSubSamples2) / sizeof(SubSample),
.imemSizeActual = sizeof(kInBinaryBuffer),
.imemOffset = 0,
.imemSize = sizeof(kInBinaryBuffer),
.srcOffset = 0,
.dstOffset = 0}));
EXPECT_EQ(Status::BAD_VALUE, descrambleStatus.getServiceSpecificError());
EXPECT_TRUE(mDescrambler->release().isOk());
}
EXPECT_TRUE(mMediaCas->release().isOk());
}
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MediaCasAidlTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, MediaCasAidlTest,
testing::ValuesIn(android::getAidlHalInstanceNames(IMediaCasService::descriptor)),
android::PrintInstanceNameToString);
// Start thread pool to receive callbacks from AIDL service.
int main(int argc, char** argv) {
InitGoogleTest(&argc, argv);
ABinderProcess_setThreadPoolMaxThreadCount(1);
ABinderProcess_startThreadPool();
return RUN_ALL_TESTS();
}

View File

@@ -182,6 +182,13 @@
<instance>default</instance>
</interface>
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.cas</name>
<interface>
<name>IMediaCasService</name>
<instance>default</instance>
</interface>
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.confirmationui</name>
<version>1</version>