在本文中,我们将详细介绍android-邀请多人游戏时发送通知(GameServices)的各个方面,并为您提供关于邀请别人的游戏的相关解答,同时,我们也将为您带来关于Android8.0实现发送通知
在本文中,我们将详细介绍android-邀请多人游戏时发送通知(Game Services)的各个方面,并为您提供关于邀请别人的游戏的相关解答,同时,我们也将为您带来关于Android 8.0实现发送通知、Android 9-KeyStore异常android.os.ServiceSpecificException、Android Camera 三 CameraService 和 Client 链接到 HAL、Android Camera 原理之 camera service 与 camera provider session 会话与 capture request 轮转的有用知识。
本文目录一览:- android-邀请多人游戏时发送通知(Game Services)(邀请别人的游戏)
- Android 8.0实现发送通知
- Android 9-KeyStore异常android.os.ServiceSpecificException
- Android Camera 三 CameraService 和 Client 链接到 HAL
- Android Camera 原理之 camera service 与 camera provider session 会话与 capture request 轮转
android-邀请多人游戏时发送通知(Game Services)(邀请别人的游戏)
我正在玩Google Play游戏服务和多人游戏支持.如果我邀请玩家使用这项服务,是否可以自动将通知发送给接收者?当我使用演示项目时,不会发生这种情况. documentation却说:
If the signed-in player accepts an invitation from the notification area on the Android status bar, your app should accept the invitation and go directly to the game screen (skipping the main menu).
这并不是明确表示支持通知,但至少给了我一些希望:-).根据此问题:似乎支持Google play game services invitations get lost通知,但是我从未收到任何通知.
解决方法:
通知是受支持的,并将被发送到接收方的玩家…如果玩家不在彼此的圈子中,则有时不会显示该通知,具体取决于接收者的设置.也许那就是为什么你什么都没收到?
Android 8.0实现发送通知
在Android8.0以后,针对Notification 通知api做了修改,新增了通知渠道(NotificationCannel)。下面就把demo的详细代码记录下:
1.Application 为NotificationManager添加通知频道
import android.app.Application; import com.xinrui.ndkapp.notification.NotificationChannels; public class NdkApplication extends Application { @Override public void onCreate() { super.onCreate(); NotificationChannels.createAllNotificationChannels(this); } }
2.NotificationChannels 类
public class NotificationChannels { public final static String CRITICAL = "critical"; public final static String IMPORTANCE = "importance"; public final static String DEFAULT = "default"; public final static String LOW = "low"; public final static String MEDIA = "media"; public static void createAllNotificationChannels(Context context) { NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); if(nm == null) { return; } NotificationChannel mediaChannel = new NotificationChannel( MEDIA, context.getString(R.string.app_name), NotificationManager.IMPORTANCE_DEFAULT); mediaChannel.setSound(null,null); mediaChannel.setVibrationPattern(null); nm.createNotificationChannels(Arrays.asList( new NotificationChannel( CRITICAL, context.getString(R.string.app_name), NotificationManager.IMPORTANCE_HIGH), new NotificationChannel( IMPORTANCE, context.getString(R.string.app_name), NotificationManager.IMPORTANCE_DEFAULT), new NotificationChannel( DEFAULT, context.getString(R.string.app_name), NotificationManager.IMPORTANCE_LOW), new NotificationChannel( LOW, context.getString(R.string.app_name), NotificationManager.IMPORTANCE_MIN), //custom notification channel mediaChannel )); } }
3.发送通知
public void sendSimpleNotification(Context context, NotificationManager nm) { //创建点击通知时发送的广播 Intent intent = new Intent(context, NotificationMonitorService.class); intent.setAction("android.service.notification.NotificationListenerService"); PendingIntent pi = PendingIntent.getService(context,0,intent,0); //创建删除通知时发送的广播 Intent deleteIntent = new Intent(context,NotificationMonitorService.class); deleteIntent.setAction(Intent.ACTION_DELETE); PendingIntent deletePendingIntent = PendingIntent.getService(context,0,deleteIntent,0); //创建通知 Notification.Builder nb = new Notification.Builder(context, NotificationChannels.DEFAULT) //设置通知左侧的小图标 .setSmallIcon(R.drawable.ic_notification) //设置通知标题 .setContentTitle("Simple notification") //设置通知内容 .setContentText("Demo for simple notification!") //设置点击通知后自动删除通知 .setAutoCancel(true) //设置显示通知时间 .setShowWhen(true) //设置通知右侧的大图标 .setLargeIcon(BitmapFactory.decodeResource(context.getResources(),R.drawable.ic_notifiation_big)) //设置点击通知时的响应事件 .setContentIntent(pi) //设置删除通知时的响应事件 .setDeleteIntent(deletePendingIntent); //发送通知 nm.notify(Notificaitons.NOTIFICATION_SAMPLE,nb.build()); }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
- Android监听手机电话状态与发送邮件通知来电号码的方法(基于PhoneStateListene实现)
Android 9-KeyStore异常android.os.ServiceSpecificException
如果我在Android 9上运行此代码,则会收到以下异常:
private static KeyStore.PrivateKeyEntry getPrivateKeyEntry(String alias) { try { KeyStore ks = KeyStore .getInstance(SecurityConstants.KEYSTORE_PROVIDER_ANDROID_KEYSTORE); ks.load(null); KeyStore.Entry entry = ks.getEntry(alias, null); if (entry == null) { Log.w(TAG, "No key found under alias: " + alias); Log.w(TAG, "Exiting signData()..."); return null; } if (!(entry instanceof KeyStore.PrivateKeyEntry)) { Log.w(TAG, "Not an instance of a PrivateKeyEntry"); Log.w(TAG, "Exiting signData()..."); return null; } return (KeyStore.PrivateKeyEntry) entry; } catch (Exception e) { Log.e(TAG, e.getMessage(), e); return null; } }
例外:
KeyStore异常android.os.ServiceSpecificException:(代码7)在android.os.Parcel.createException(Parcel.java:1956)在android.os.Parcel.readException(Parcel.java:1910)在android.os.Parcel.readException
(Parcel.java:1860)在android.security.IKeystoreService $ Stub $
Proxy.get(IKeystoreService.java:786)在android.security.KeyStore.get(KeyStore.java:195)在android.security.keystore.AndroidKeyStoreSpi。在com.phenodev.testenc.KeyStoreHelper.getPrivateKeyEntry(KeyStoreHelper
.java:151)com.phenodev.testenc.KeyStoreHelper.encrypt(KeyStoreHelper.java:173)。phenodev.testenc.KeyStoreEncryptor.encrypt(KeyStoreEncryptor.java:19)
请帮助修复它。
答案1
小编典典终于我找到了解决方案。由于Android P (KeyStore.PrivateKeyEntry) keyStore.getEntry("alias",null)
并不是获取私钥的正确方法,因此看起来。
我可以通过这种方式访问私钥/公钥来摆脱此警告
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");keyStore.load(null);PrivateKey privateKey = (PrivateKey) keyStore.getKey("alias", null);PublicKey publicKey = keyStore.getCertificate("alias").getPublicKey();
Android Camera 三 CameraService 和 Client 链接到 HAL
Android Camera 一 源码路径
Android Camera 二 JNI JAVA 和 C/CPP 图像数据传输流程分析
Android Camera 三 CameraService 和 Client 链接到 HAL
Android Camera 四 Camera HAL 分析
Android Camera 五 Camera HAL v1
Linux v4l2 一 应用层
Linux v4l2 二 驱动和 usb 摄像头
frameworks/av/camera/Camera.cpp
frameworks/av/camera/CameraBase.cpp
frameworks/av/services/camera/libcameraservice/CameraService.cpp
frameworks/av/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
frameworks/av/services/camera/libcameraservice/common/Camera2ClientBase.cpp
frameworks/av/services/camera/libcameraservice/device3/Camera3Device.cpp
在上一章 Android camera 二 中提到的 JNI 方法。
JNI 是 JAVA 层和 native 层通讯的桥梁。在 Android 中叫 NDK (Native Development Kit )。
android_hardware_Camera_native_setup 中调用了 connect 方法,最终目标是连接到相机设备,并打开相机镜头。
// android_hardware_Camera.cpp
static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
jobject weak_this, jint cameraId, jint halVersion, jstring clientPackageName)
{
......
sp<Camera> camera;
if (halVersion == CAMERA_HAL_API_VERSION_NORMAL_CONNECT) {
// Default path: hal version is don''t care, do normal camera connect.
camera = Camera::connect(cameraId, clientName,
Camera::USE_CALLING_UID, Camera::USE_CALLING_PID);
} else {
jint status = Camera::connectLegacy(cameraId, halVersion, clientName,
Camera::USE_CALLING_UID, camera);
if (status != NO_ERROR) {
return status;
}
}
if (camera == NULL) {
return -EACCES;
}
......
}
android_hardware_Camera_native_setup 创建 Camera 智能指针,调用 Camera::connect () 方法构造 Camera 类实例。
Camera 类中的 connect 方法调用 CameraBase 类的 connect 方法获取系统的 cameraservice 并通过 binder 机制建立 camera 客户端链接。
// Camera.cpp
sp<Camera> Camera::connect(int cameraId, const String16& clientPackageName,
int clientUid, int clientPid)
{
return CameraBaseT::connect(cameraId, clientPackageName, clientUid, clientPid);
}
// CameraBase.cpp
template <typename TCam, typename TCamTraits>
sp<TCam> CameraBase<TCam, TCamTraits>::connect(int cameraId,
const String16& clientPackageName,
int clientUid, int clientPid)
{
ALOGV("%s: connect", __FUNCTION__);
sp<TCam> c = new TCam(cameraId);
sp<TCamCallbacks> cl = c;
// 获取 camera 的服务
const sp<::android::hardware::ICameraService>& cs = getCameraService();
binder::Status ret;
if(cs != nullptr)
{
/*
* 定义在 /frameworks/av/camera/Camera.cpp
* CameraTraits<Camera>::TCamConnectService CameraTraits<Camera>::fnConnectService =
* &::android::hardware::ICameraService::connect;
* 推测最终是对应 CameraService::connect
*
*/
TCamConnectService fnConnectService = TCamTraits::fnConnectService;
ret = (cs.get()->*fnConnectService)(cl, cameraId, clientPackageName, clientUid,
clientPid, /*out*/ &c->mCamera);
}
if(ret.isOk() && c->mCamera != nullptr)
{
// Binder 对象设置死亡代理。当出现和服务端连接发生故障时,系统将自动调用死亡代理函数 binderDied ()
// 为 Binder 对象设置死亡代理
IInterface::asBinder(c->mCamera)->linkToDeath(c);
c->mStatus = NO_ERROR;
}
else
{
ALOGW("An error occurred while connecting to camera %d: %s", cameraId,
(cs != nullptr) ? "Service not available" : ret.toString8().string());
c.clear();
}
return c;
}
CameraBase 类的 connect () 调用 getCameraService () 获取 camera 服务
// CameraBase.cpp
// establish binder interface to camera service
template <typename TCam, typename TCamTraits>
const sp<::android::hardware::ICameraService>& CameraBase<TCam, TCamTraits>::getCameraService()
{
Mutex::Autolock _l(gLock);
if(gCameraService.get() == 0)
{
// 获取系统服务列表
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
do
{
// 通过 kCameraServiceName 字符串获取相机服务
binder = sm->getService(String16(kCameraServiceName));
if(binder != 0)
{
break;
}
ALOGW("CameraService not published, waiting...");
usleep(kCameraServicePollDelay);
}
while(true);
if(gDeathNotifier == NULL)
{
gDeathNotifier = new DeathNotifier();
}
binder->linkToDeath(gDeathNotifier);
//find -name ICameraService.h 在 out 目录下有这个文件,不知道为什么编译的 out 目录会生成这个文件
// ./out/obj_arm/SHARED_LIBRARIES/libcamera_client_intermediates/aidl-generated/include/android/hardware/ICameraService.h
// ./out/obj/SHARED_LIBRARIES/libcamera_client_intermediates/aidl-generated/include/android/hardware/ICameraService.h
gCameraService = interface_cast<::android::hardware::ICameraService>(binder);
}
ALOGE_IF(gCameraService == 0, "no CameraService!?");
return gCameraService;
}
Camera 框架使用 binder 机制和 CameraListener 类的纯虚函数,实现跨进程传输图像数据。这里不叙述 binder 机制。
简单介绍下 cameraservice 的 serivce 和 client 端是的调用关系,是怎么连接到 HAL 层。
相机的 CameraService 是提供相机服务端实现的类,从 CameraService::connect () 开始逐步靠近 HAL 层的厂商相机注册函数集。
// frameworks/av/services/camera/libcameraservice/CameraService.cpp
Status CameraService::connect(
const sp<ICameraClient>& cameraClient,
int cameraId,
const String16& clientPackageName,
int clientUid,
int clientPid,
/*out*/
sp<ICamera>* device) {
ATRACE_CALL();
Status ret = Status::ok();
String8 id = String8::format("%d", cameraId);
sp<Client> client = nullptr;
// 模板 connectHelper 里获取 camera client 代理
ret = connectHelper<ICameraClient,Client>(cameraClient, id,
CAMERA_DEVICE_API_VERSION_1_0/* modified */, clientPackageName, clientUid, clientPid, API_1,
/*legacyMode*/ true/* modified */, /*shimUpdateOnly*/ false,
/*out*/client);
if(!ret.isOk()) {
logRejected(id, getCallingPid(), String8(clientPackageName),
ret.toString8());
return ret;
}
*device = client;
return ret;
}
CameraService::connectHelper 模板里调用 makeClient () 函数
template<class CALLBACK, class CLIENT>
binder::Status CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId,
int halVersion, const String16& clientPackageName, int clientUid, int clientPid,
apiLevel effectiveApiLevel, bool legacyMode, bool shimUpdateOnly,
/*out*/sp<CLIENT>& device)
{
......
if(!(ret = makeClient(this, cameraCb, clientPackageName, id, facing, clientPid,
clientUid, getpid(), legacyMode, halVersion, deviceVersion, effectiveApiLevel,
/*out*/&tmp)).isOk())
{
return ret;
}
......
}
Android7 使用的 Camera API 2.0,所以 CameraService::makeClient () 调用 *client = new CameraDeviceClient 进入 CameraDeviceClient.cpp
Status CameraService::makeClient(const sp<CameraService>& cameraService,
const sp<IInterface>& cameraCb, const String16& packageName, int cameraId,
int facing, int clientPid, uid_t clientUid, int servicePid, bool legacyMode,
int halVersion, int deviceVersion, apiLevel effectiveApiLevel,
/*out*/sp<BasicClient>* client)
{
if(halVersion < 0 || halVersion == deviceVersion)
{
// Default path: HAL version is unspecified by caller, create CameraClient
// based on device version reported by the HAL.
switch(deviceVersion)
{
case CAMERA_DEVICE_API_VERSION_1_0:
if(effectiveApiLevel == API_1) // Camera1 API route
{
sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
*client = new CameraClient(cameraService, tmp, packageName, cameraId, facing,
clientPid, clientUid, getpid(), legacyMode);
}
else // Camera2 API route
{
ALOGW("Camera using old HAL version: %d", deviceVersion);
return STATUS_ERROR_FMT(ERROR_DEPRECATED_HAL,
"Camera device \"%d\" HAL version %d does not support camera2 API",
cameraId, deviceVersion);
}
break;
case CAMERA_DEVICE_API_VERSION_3_0:
case CAMERA_DEVICE_API_VERSION_3_1:
case CAMERA_DEVICE_API_VERSION_3_2:
case CAMERA_DEVICE_API_VERSION_3_3:
case CAMERA_DEVICE_API_VERSION_3_4:
if(effectiveApiLevel == API_1) // Camera1 API route
{
sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
*client = new Camera2Client(cameraService, tmp, packageName, cameraId, facing,
clientPid, clientUid, servicePid, legacyMode);
}
else // Camera2 API route 创建 CameraDeviceClient
{
sp<hardware::camera2::ICameraDeviceCallbacks> tmp =
static_cast<hardware::camera2::ICameraDeviceCallbacks*>(cameraCb.get());
*client = new CameraDeviceClient(cameraService, tmp, packageName, cameraId,
facing, clientPid, clientUid, servicePid);
}
break;
default:
// Should not be reachable
ALOGE("Unknown camera device HAL version: %d", deviceVersion);
return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
"Camera device \"%d\" has unknown HAL version %d",
cameraId, deviceVersion);
}
}
else
{
......
}
return Status::ok();
}
CameraDeviceClient 类的构造函数调用 Camera2ClientBase 模板函数执行 mDevice = new Camera3Device (cameraId); 创建 Camera3Device 类的实例。
// frameworks/av/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
// Interface used by CameraService
CameraDeviceClient::CameraDeviceClient(const sp<CameraService>& cameraService,
const sp<hardware::camera2::ICameraDeviceCallbacks>& remoteCallback,
const String16& clientPackageName,
int cameraId,
int cameraFacing,
int clientPid,
uid_t clientUid,
int servicePid) :
Camera2ClientBase(cameraService, remoteCallback, clientPackageName,
cameraId, cameraFacing, clientPid, clientUid, servicePid),
mInputStream(),
mStreamingRequestId(REQUEST_ID_NONE),
mRequestIdCounter(0)
{
ATRACE_CALL();
ALOGI("CameraDeviceClient %d: Opened", cameraId);
}
// frameworks/av/services/camera/libcameraservice/common/Camera2ClientBase.cpp
// Interface used by CameraService
template <typename TClientBase>
Camera2ClientBase<TClientBase>::Camera2ClientBase(
const sp<CameraService>& cameraService,
const sp<TCamCallbacks>& remoteCallback,
const String16& clientPackageName,
int cameraId,
int cameraFacing,
int clientPid,
uid_t clientUid,
int servicePid):
TClientBase(cameraService, remoteCallback, clientPackageName,
cameraId, cameraFacing, clientPid, clientUid, servicePid),
mSharedCameraCallbacks(remoteCallback),
mDeviceVersion(cameraService->getDeviceVersion(cameraId)),
mDeviceActive(false)
{
ALOGI("Camera %d: Opened. Client: %s (PID %d, UID %d)", cameraId,
String8(clientPackageName).string(), clientPid, clientUid);
mInitialClientPid = clientPid;
mDevice = new Camera3Device(cameraId);
LOG_ALWAYS_FATAL_IF(mDevice == 0, "Device should never be NULL here.");
}
创建 Camera3Device () 实例;在该类的初始化方法 Camera3Device::initialize (CameraModule *module) 中调用模块的 open () 函数,打开相机设备。进入 HAL 层。
// frameworks/av/services/camera/libcameraservice/device3/Camera3Device.cpp
Camera3Device::Camera3Device(int id):
mId(id),
mIsConstrainedHighSpeedConfiguration(false),
mHal3Device(NULL),
mStatus(STATUS_UNINITIALIZED),
mStatusWaiters(0),
mUsePartialResult(false),
mNumPartialResults(1),
mTimestampOffset(0),
mNextResultFrameNumber(0),
mNextReprocessResultFrameNumber(0),
mNextShutterFrameNumber(0),
mNextReprocessShutterFrameNumber(0),
mListener(NULL)
{
ATRACE_CALL();
camera3_callback_ops::notify = &sNotify;
camera3_callback_ops::process_capture_result = &sProcessCaptureResult;
ALOGV("%s: Created device for camera %d", __FUNCTION__, id);
}
// frameworks/av/services/camera/libcameraservice/device3/Camera3Device.cpp
// 该函数中 module->open () ,调用 HAL 层注册的相机模块 open 函数
status_t Camera3Device::initialize(CameraModule *module)
{
ATRACE_CALL();
Mutex::Autolock il(mInterfaceLock);
Mutex::Autolock l(mLock);
ALOGV("%s: Initializing device for camera %d", __FUNCTION__, mId);
if (mStatus != STATUS_UNINITIALIZED) {
CLOGE("Already initialized!");
return INVALID_OPERATION;
}
/** Open HAL device */
status_t res;
String8 deviceName = String8::format("%d", mId);
camera3_device_t *device;
ATRACE_BEGIN("camera3->open");
res = module->open(deviceName.string(),
reinterpret_cast<hw_device_t**>(&device)); // 打开相机设备
ATRACE_END();
if (res != OK) {
SET_ERR_L("Could not open camera: %s (%d)", strerror(-res), res);
return res;
}
/** Cross-check device version */
if (device->common.version < CAMERA_DEVICE_API_VERSION_3_0) {
SET_ERR_L("Could not open camera: "
"Camera device should be at least %x, reports %x instead",
CAMERA_DEVICE_API_VERSION_3_0,
device->common.version);
device->common.close(&device->common);
return BAD_VALUE;
}
camera_info info;
res = module->getCameraInfo(mId, &info);
if (res != OK) return res;
if (info.device_version != device->common.version) {
SET_ERR_L("HAL reporting mismatched camera_info version (%x)"
" and device version (%x).",
info.device_version, device->common.version);
device->common.close(&device->common);
return BAD_VALUE;
}
......
return OK;
}
至此代码进入 HAL 空间。 HAL 没有 Framework 那么复杂的。 Android 其他模块代码的调用流程可参考 Camera 。如果做驱动开发又想了解 Android framework 框架,建议先跳过 Java 层代码。从 CPP 开始跟代码,逐步理解 Framework 与 HAL 的关系。然后再跟 Java 层的代码。
Android Camera 原理之 camera service 与 camera provider session 会话与 capture request 轮转
上层调用 CameraManager.openCamera 的时候,会触发底层的一系列反应,之前我们分享过 camera framework 到 camera service 之间的调用,但是光看这一块还不够深入,接下来我们讨论一下 camera service 与 camera provider 之间在 openCamera 调用的时候做了什么事情。
status_t Camera3Device::initialize(sp<CameraProviderManager> manager, const String8& monitorTags) {
sp<ICameraDeviceSession> session;
status_t res = manager->openSession(mId.string(), this,
/*out*/ &session);
//......
res = manager->getCameraCharacteristics(mId.string(), &mDeviceInfo);
//......
std::shared_ptr<RequestMetadataQueue> queue;
auto requestQueueRet = session->getCaptureRequestMetadataQueue(
[&queue](const auto& descriptor) {
queue = std::make_shared<RequestMetadataQueue>(descriptor);
if (!queue->isValid() || queue->availableToWrite() <= 0) {
ALOGE("HAL returns empty request metadata fmq, not use it");
queue = nullptr;
// don''t use the queue onwards.
}
});
//......
std::unique_ptr<ResultMetadataQueue>& resQueue = mResultMetadataQueue;
auto resultQueueRet = session->getCaptureResultMetadataQueue(
[&resQueue](const auto& descriptor) {
resQueue = std::make_unique<ResultMetadataQueue>(descriptor);
if (!resQueue->isValid() || resQueue->availableToWrite() <= 0) {
ALOGE("HAL returns empty result metadata fmq, not use it");
resQueue = nullptr;
// Don''t use the resQueue onwards.
}
});
//......
mInterface = new HalInterface(session, queue);
std::string providerType;
mVendorTagId = manager->getProviderTagIdLocked(mId.string());
mTagMonitor.initialize(mVendorTagId);
if (!monitorTags.isEmpty()) {
mTagMonitor.parseTagsToMonitor(String8(monitorTags));
}
return initializeCommonLocked();
}
上面 camera service 中执行 openCamera 中的核心步骤,可以看出,第一步执行的就是 manager->openSession (mId.string (), this, /out/ &session);
本文就是通过剖析 openSession 的执行流程来 还原 camera service 与 camera provider 的执行过程。
CameraProviderManager--openSession 流程.jpg
为了让大家看得更加清楚,列出各个文件的位置:
CameraProviderManager : frameworks/av/services/camera/libcameraservice/common/CameraServiceProvider.cpp
CameraDevice : hardware/interfaces/camera/device/3.2/default/CameraDevice.cpp
CameraModule : hardware/interfaces/camera/common/1.0/default/CameraModule.cpp
CameraHAL : hardware/libhardware/modules/camera/3_0/CameraHAL.cpp
Camera : hardware/libhardware/modules/camera/3_0/Camera.cpp
CameraDeviceSession : hardware/interfaces/camera/device/3.2/default/CameraDeviceSession.cpp
中间涉及到一些指针函数的映射,如果看不明白,可以参考:《Android Camera 原理之底层数据结构总结》,具体的调用流程就不说了,按照上面的时序图走,都能看明白的。
一些回调关系还是值得说下的。我们看下 CameraProviderManager::openSession 调用的地方:
status_t CameraProviderManager::openSession(const std::string &id,
const sp<hardware::camera::device::V3_2::ICameraDeviceCallback>& callback,
/*out*/
sp<hardware::camera::device::V3_2::ICameraDeviceSession> *session) {
std::lock_guard<std::mutex> lock(mInterfaceMutex);
auto deviceInfo = findDeviceInfoLocked(id,
/*minVersion*/ {3,0}, /*maxVersion*/ {4,0});
if (deviceInfo == nullptr) return NAME_NOT_FOUND;
auto *deviceInfo3 = static_cast<ProviderInfo::DeviceInfo3*>(deviceInfo);
Status status;
hardware::Return<void> ret;
ret = deviceInfo3->mInterface->open(callback, [&status, &session]
(Status s, const sp<device::V3_2::ICameraDeviceSession>& cameraSession) {
status = s;
if (status == Status::OK) {
*session = cameraSession;
}
});
if (!ret.isOk()) {
ALOGE("%s: Transaction error opening a session for camera device %s: %s",
__FUNCTION__, id.c_str(), ret.description().c_str());
return DEAD_OBJECT;
}
return mapToStatusT(status);
}
我们看下 IPC 调用的地方:
ret = deviceInfo3->mInterface->open(callback, [&status, &session]
(Status s, const sp<device::V3_2::ICameraDeviceSession>& cameraSession) {
status = s;
if (status == Status::OK) {
*session = cameraSession;
}
});
传入两个参数,一个是 const sp<hardware::camera::device::V3_2::ICameraDeviceCallback>& callback, 另一个是 open_cb _hidl_cb
callback 提供了 camera HAL 层到 camera service 的回调。
open_cb _hidl_cb 是硬件抽象层提供了一种 IPC 间回传数据的方式。就本段代码而言,需要传回两个数据,一个 status:表示当前 openSession 是否成功;另一个是 session:表示 camera session 会话创建成功之后返回的 session 数据。
CameraDevice::open (...) 函数
{
session = createSession(
device, info.static_camera_characteristics, callback);
if (session == nullptr) {
ALOGE("%s: camera device session allocation failed", __FUNCTION__);
mLock.unlock();
_hidl_cb(Status::INTERNAL_ERROR, nullptr);
return Void();
}
if (session->isInitFailed()) {
ALOGE("%s: camera device session init failed", __FUNCTION__);
session = nullptr;
mLock.unlock();
_hidl_cb(Status::INTERNAL_ERROR, nullptr);
return Void();
}
mSession = session;
IF_ALOGV() {
session->getInterface()->interfaceChain([](
::android::hardware::hidl_vec<::android::hardware::hidl_string> interfaceChain) {
ALOGV("Session interface chain:");
for (auto iface : interfaceChain) {
ALOGV(" %s", iface.c_str());
}
});
}
mLock.unlock();
}
_hidl_cb(status, session->getInterface());
最后执行的代码 _hidl_cb (status, session→getInterface ()); 当前 session 创建成功之后,回调到 camera service 中。
const sp<hardware::camera::device::V3_2::ICameraDeviceCallback>& callback 设置到什么地方?这个问题非常重要的,camera 上层很依赖底层的回调,所以我们要搞清楚底层的回调被设置到什么地方,然后在搞清楚在合适的时机触发这些回调。
执行 CameraDeviceSession 构造函数的时候,传入了这个 callback。
CameraDeviceSession::CameraDeviceSession(
camera3_device_t* device,
const camera_metadata_t* deviceInfo,
const sp<ICameraDeviceCallback>& callback) :
camera3_callback_ops({&sProcessCaptureResult, &sNotify}),
mDevice(device),
mDeviceVersion(device->common.version),
mIsAELockAvailable(false),
mDerivePostRawSensKey(false),
mNumPartialResults(1),
mResultBatcher(callback) {
mDeviceInfo = deviceInfo;
camera_metadata_entry partialResultsCount =
mDeviceInfo.find(ANDROID_REQUEST_PARTIAL_RESULT_COUNT);
if (partialResultsCount.count > 0) {
mNumPartialResults = partialResultsCount.data.i32[0];
}
mResultBatcher.setNumPartialResults(mNumPartialResults);
camera_metadata_entry aeLockAvailableEntry = mDeviceInfo.find(
ANDROID_CONTROL_AE_LOCK_AVAILABLE);
if (aeLockAvailableEntry.count > 0) {
mIsAELockAvailable = (aeLockAvailableEntry.data.u8[0] ==
ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE);
}
// Determine whether we need to derive sensitivity boost values for older devices.
// If post-RAW sensitivity boost range is listed, so should post-raw sensitivity control
// be listed (as the default value 100)
if (mDeviceInfo.exists(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE)) {
mDerivePostRawSensKey = true;
}
mInitFail = initialize();
}
CameraDeviceSession 中的 mResultBatcher 类构造中传入了这个 callback,现在由 CameraDeviceSession::ResultBatcher 来持有 callback 了。看下 ResultBatcher 全局代码,在 CameraDeviceSession.h 中。
那以后底层要回调到上层必定要经过 CameraDeviceSession::ResultBatcher 的 mCallback 来完成了。
class ResultBatcher {
public:
ResultBatcher(const sp<ICameraDeviceCallback>& callback);
void setNumPartialResults(uint32_t n);
void setBatchedStreams(const std::vector<int>& streamsToBatch);
void setResultMetadataQueue(std::shared_ptr<ResultMetadataQueue> q);
void registerBatch(uint32_t frameNumber, uint32_t batchSize);
void notify(NotifyMsg& msg);
void processCaptureResult(CaptureResult& result);
protected:
struct InflightBatch {
// Protect access to entire struct. Acquire this lock before read/write any data or
// calling any methods. processCaptureResult and notify will compete for this lock
// HIDL IPCs might be issued while the lock is held
Mutex mLock;
bool allDelivered() const;
uint32_t mFirstFrame;
uint32_t mLastFrame;
uint32_t mBatchSize;
bool mShutterDelivered = false;
std::vector<NotifyMsg> mShutterMsgs;
struct BufferBatch {
BufferBatch(uint32_t batchSize) {
mBuffers.reserve(batchSize);
}
bool mDelivered = false;
// This currently assumes every batched request will output to the batched stream
// and since HAL must always send buffers in order, no frameNumber tracking is
// needed
std::vector<StreamBuffer> mBuffers;
};
// Stream ID -> VideoBatch
std::unordered_map<int, BufferBatch> mBatchBufs;
struct MetadataBatch {
// (frameNumber, metadata)
std::vector<std::pair<uint32_t, CameraMetadata>> mMds;
};
// Partial result IDs that has been delivered to framework
uint32_t mNumPartialResults;
uint32_t mPartialResultProgress = 0;
// partialResult -> MetadataBatch
std::map<uint32_t, MetadataBatch> mResultMds;
// Set to true when batch is removed from mInflightBatches
// processCaptureResult and notify must check this flag after acquiring mLock to make
// sure this batch isn''t removed while waiting for mLock
bool mRemoved = false;
};
// Get the batch index and pointer to InflightBatch (nullptrt if the frame is not batched)
// Caller must acquire the InflightBatch::mLock before accessing the InflightBatch
// It''s possible that the InflightBatch is removed from mInflightBatches before the
// InflightBatch::mLock is acquired (most likely caused by an error notification), so
// caller must check InflightBatch::mRemoved flag after the lock is acquried.
// This method will hold ResultBatcher::mLock briefly
std::pair<int, std::shared_ptr<InflightBatch>> getBatch(uint32_t frameNumber);
static const int NOT_BATCHED = -1;
// move/push function avoids "hidl_handle& operator=(hidl_handle&)", which clones native
// handle
void moveStreamBuffer(StreamBuffer&& src, StreamBuffer& dst);
void pushStreamBuffer(StreamBuffer&& src, std::vector<StreamBuffer>& dst);
void sendBatchMetadataLocked(
std::shared_ptr<InflightBatch> batch, uint32_t lastPartialResultIdx);
// Check if the first batch in mInflightBatches is ready to be removed, and remove it if so
// This method will hold ResultBatcher::mLock briefly
void checkAndRemoveFirstBatch();
// The following sendXXXX methods must be called while the InflightBatch::mLock is locked
// HIDL IPC methods will be called during these methods.
void sendBatchShutterCbsLocked(std::shared_ptr<InflightBatch> batch);
// send buffers for all batched streams
void sendBatchBuffersLocked(std::shared_ptr<InflightBatch> batch);
// send buffers for specified streams
void sendBatchBuffersLocked(
std::shared_ptr<InflightBatch> batch, const std::vector<int>& streams);
// End of sendXXXX methods
// helper methods
void freeReleaseFences(hidl_vec<CaptureResult>&);
void notifySingleMsg(NotifyMsg& msg);
void processOneCaptureResult(CaptureResult& result);
void invokeProcessCaptureResultCallback(hidl_vec<CaptureResult> &results, bool tryWriteFmq);
// Protect access to mInflightBatches, mNumPartialResults and mStreamsToBatch
// processCaptureRequest, processCaptureResult, notify will compete for this lock
// Do NOT issue HIDL IPCs while holding this lock (except when HAL reports error)
mutable Mutex mLock;
std::deque<std::shared_ptr<InflightBatch>> mInflightBatches;
uint32_t mNumPartialResults;
std::vector<int> mStreamsToBatch;
const sp<ICameraDeviceCallback> mCallback;
std::shared_ptr<ResultMetadataQueue> mResultMetadataQueue;
// Protect against invokeProcessCaptureResultCallback()
Mutex mProcessCaptureResultLock;
} mResultBatcher;
到这里,openSession 工作就完成了,这个主要是设置了上层的回调到底层,并且底层返回可用的 camera session 到上层来,实现底层和上层的交互通信。
1. 获取的 session 是什么?为什么这个重要?
此 session 是 ICameraDeviceSession 对象,这个对象是指为了操作 camera device,camera provider 与 camera service 之间建立的一个会话机制,可以保证 camera service IPC 调用到 camera provider 进程中的代码。
1.1. 获取 session 当前请求原数组队列
auto requestQueueRet = session->getCaptureRequestMetadataQueue(
[&queue](const auto& descriptor) {
queue = std::make_shared<RequestMetadataQueue>(descriptor);
if (!queue->isValid() || queue->availableToWrite() <= 0) {
ALOGE("HAL returns empty request metadata fmq, not use it");
queue = nullptr;
// don''t use the queue onwards.
}
});
到 HAL 层的 CameraDeviceSession.cpp 中调用 getCaptureRequestMetadataQueue
Return<void> CameraDeviceSession::getCaptureRequestMetadataQueue(
ICameraDeviceSession::getCaptureRequestMetadataQueue_cb _hidl_cb) {
_hidl_cb(*mRequestMetadataQueue->getDesc());
return Void();
}
这个 mRequestMetadataQueue 是在 CameraDeviceSession::initialize 执行的时候初始化的。
int32_t reqFMQSize = property_get_int32("ro.camera.req.fmq.size", /*default*/-1);
if (reqFMQSize < 0) {
reqFMQSize = CAMERA_REQUEST_METADATA_QUEUE_SIZE;
} else {
ALOGV("%s: request FMQ size overridden to %d", __FUNCTION__, reqFMQSize);
}
mRequestMetadataQueue = std::make_unique<RequestMetadataQueue>(
static_cast<size_t>(reqFMQSize),
false /* non blocking */);
if (!mRequestMetadataQueue->isValid()) {
ALOGE("%s: invalid request fmq", __FUNCTION__);
return true;
}
首先读取 ro.camera.req.fmq.size 属性,如果没有找到,则直接赋给一个 1M 大小的 请求原数组队列。这个队列很重要,后续的 camera capture 请求都是通过这个队列处理的。
1.2. 获取 session 当前结果原数组队列
这个和 请求原数组队列相似,不过结果原数组中保留的是 camera capture 的结果数据。大家可以看下源码,这儿就不贴源码了
2. 开始运转 capture request 线程
camera service 与 camera provider 建立 session 会话之后,开始运转 capture request 请求线程,之后发送的 capture request 都会到这个线程中执行,这就是熟知的 capture request 轮转。
在 Camera3Device::initializeCommonLocked 中执行了 capture request 轮转。
/** Start up request queue thread */
mRequestThread = new RequestThread(this, mStatusTracker, mInterface, sessionParamKeys);
res = mRequestThread->run(String8::format("C3Dev-%s-ReqQueue", mId.string()).string());
if (res != OK) {
SET_ERR_L("Unable to start request queue thread: %s (%d)",
strerror(-res), res);
mInterface->close();
mRequestThread.clear();
return res;
}
开始启动当前的 capture request 队列,放在 RequestThread 线程中执行,这个线程会一直执行,当有新的 capture request 发过来,会将 capture request 放进当前会话的请求队列中,继续执行。这个轮转很重要,这是 camera 能正常工作的前提。
轮转的主要工作在 Camera3Device::RequestThread::threadLoop 函数中完成,这是 native 中定义的一个 线程执行函数块。
bool Camera3Device::RequestThread::threadLoop() {
ATRACE_CALL();
status_t res;
// Handle paused state.
if (waitIfPaused()) {
return true;
}
// Wait for the next batch of requests.
waitForNextRequestBatch();
if (mNextRequests.size() == 0) {
return true;
}
//......
// Prepare a batch of HAL requests and output buffers.
res = prepareHalRequests();
if (res == TIMED_OUT) {
// Not a fatal error if getting output buffers time out.
cleanUpFailedRequests(/*sendRequestError*/ true);
// Check if any stream is abandoned.
checkAndStopRepeatingRequest();
return true;
} else if (res != OK) {
cleanUpFailedRequests(/*sendRequestError*/ false);
return false;
}
// Inform waitUntilRequestProcessed thread of a new request ID
{
Mutex::Autolock al(mLatestRequestMutex);
mLatestRequestId = latestRequestId;
mLatestRequestSignal.signal();
}
//......
bool submitRequestSuccess = false;
nsecs_t tRequestStart = systemTime(SYSTEM_TIME_MONOTONIC);
if (mInterface->supportBatchRequest()) {
submitRequestSuccess = sendRequestsBatch();
} else {
submitRequestSuccess = sendRequestsOneByOne();
}
//......
return submitRequestSuccess;
}
waitForNextRequestBatch () 不断去轮训底层是否有 InputBuffer 数据,获取的 inputBuffer 数据放在 request 中,这些数据会在之后被消费。
这儿先列个调用过程:对照着代码看一下,camera 的 producer 与 consumer 模型之后还会详细讲解的。
camera request 轮转流程.jpg
这儿也为了大家快速进入代码,也列出来代码的对应位置:
Camera3Device::RequestThread : frameworks/av/services/camera/libcameraservice/device3/Camera3Device.cpp 中有内部类 RequestThread,这是一个线程类。
Camera3Stream : frameworks/av/services/camera/libcameraservice/device3/Camera3Stream.cpp
Camera3InputStream : frameworks/av/services/camera/libcameraservice/device3/Camera3InputStream.cpp
Camera3IOStreamBase : frameworks/av/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
BufferItemConsumer : frameworks/native/libs/gui/BufferItemConsumer.cpp
ConsumerBase : frameworks/native/libs/gui/ConsumerBase.cpp
BnGraphicBufferConsumer : frameworks/native/libs/gui/IGraphicBufferConsumer.cpp
上层发过来来的 capture request,手下到底层申请 Consumer buffer,这个 buffer 数据存储在 capture request 缓存中,后期这些 buffer 数据会被复用,不断地生产数据,也不断地被消费。
capture request 开启之后,camera hal 层也会受到 capture request 批处理请求,让 camera hal 做好准备,开始和 camera driver 层交互。hal 层的请求下一章讲解。
小礼物走一走,来简书关注我
关于android-邀请多人游戏时发送通知(Game Services)和邀请别人的游戏的介绍已经告一段落,感谢您的耐心阅读,如果想了解更多关于Android 8.0实现发送通知、Android 9-KeyStore异常android.os.ServiceSpecificException、Android Camera 三 CameraService 和 Client 链接到 HAL、Android Camera 原理之 camera service 与 camera provider session 会话与 capture request 轮转的相关信息,请在本站寻找。
本文标签: