当前位置: 首页 > news >正文

Android 调用系统服务接口获取屏幕投影(需要android.uid.system)

在这里插入图片描述

媒体投影

借助 Android 5(API 级别 21)中引入的 android.media.projection API,您可以将设备屏幕中的内容截取为可播放、录制或投屏到其他设备(如电视)的媒体流。

Android 14(API 级别 34)引入了应用屏幕共享功能,让用户能够分享单个应用窗口(而非整个设备屏幕),无论窗口模式如何。应用屏幕共享功能会将状态栏、导航栏、通知和其他系统界面元素从共享显示屏中排除,即使应用屏幕共享功能用于全屏截取应用也是如此。系统只会分享所选应用的内容。

应用屏幕共享功能可让用户运行多个应用,但仅限于与单个应用共享内容,从而确保用户隐私、提高用户工作效率并增强多任务处理能力。

权限

如果您的应用以 Android 14 或更高版本为目标平台,则应用清单必须包含 mediaProjection 前台服务类型的权限声明:

<manifest ...><uses-permission android:name="android.permission.FOREGROUND_SERVICE" /><uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" /><application ...><serviceandroid:name=".MyMediaProjectionService"android:foregroundServiceType="mediaProjection"android:exported="false"></service></application>
</manifest>

通过调用 startForeground() 启动媒体投影服务。

如果您未在调用中指定前台服务类型,则类型默认为清单中定义的前台服务类型的按位整数。如果清单未指定任何服务类型,系统会抛出 MissingForegroundServiceTypeException

获取MediaProjection示例(常规实现)

AndroidManifest.xml

    <!-- MediaProjection --><uses-permission android:name="android.permission.FOREGROUND_SERVICE" /><uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" /><application><activity android:name=".MediaProjectionTest"/><service android:name=".MediaProjectionService"android:foregroundServiceType="mediaProjection"/></application>

Activity

    MediaProjectionManager projMgr;final int REQUEST_CODE = 0x101;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);projMgr = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);startService(new Intent(this, ForgroundMediaProjectionService.class));startActivityForResult(projMgr.createScreenCaptureIntent(), REQUEST_CODE);}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {if(requestCode == REQUEST_CODE){MediaProjection mp = projMgr.getMediaProjection(resultCode, data);if(mp != null){//mp.stop();//获取到MediaProjection后可以通过MediaCodec编码生成图片/视频/H264流...}}}

Service

	@Overridepublic void onCreate() {super.onCreate();}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Notification notification = null;Intent activity = new Intent(this, MediaProjectionTest.class);activity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {NotificationChannel channel = new NotificationChannel("ScreenRecorder", "Foreground notification",NotificationManager.IMPORTANCE_DEFAULT);NotificationManager manager = getSystemService(NotificationManager.class);manager.createNotificationChannel(channel);notification = new Notification.Builder(this, "ScreenRecorder").setContentTitle("Test").setContentText("Test Screencast...").setContentIntent(PendingIntent.getActivity(this, 0x77,activity, PendingIntent.FLAG_UPDATE_CURRENT)).build();}startForeground(1, notification);return super.onStartCommand(intent, flags, startId);}@Overridepublic IBinder onBind(Intent intent) {return null;}

启动Acrtivity后会弹出授权提示
在这里插入图片描述
点击立即开始 Activity.onActivityResult 可以获取到MediaProjection.


如果App是系统应用(android.uid.systtem), 如何跳过授权窗?

  1. 申请MediaProjection过程拆解

涉及源码
frameworks/base/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
frameworks/base/media/java/android/media/projection/MediaProjectionManager.java
frameworks/base/core/res/res/values/config.xml
frameworks/base/packages/SystemUI/AndroidManifest.xml
frameworks/base/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java

函数createScreenCaptureIntent 返回的Intent 指向的是 SystemUI的一个组件:

frameworks/base/media/java/android/media/projection/MediaProjectionManager.java

/*** Returns an Intent that <b>must</b> be passed to startActivityForResult()* in order to start screen capture. The activity will prompt* the user whether to allow screen capture.  The result of this* activity should be passed to getMediaProjection.*/public Intent createScreenCaptureIntent() {Intent i = new Intent();final ComponentName mediaProjectionPermissionDialogComponent =ComponentName.unflattenFromString(mContext.getResources().getString(com.android.internal.R.string.config_mediaProjectionPermissionDialogComponent));i.setComponent(mediaProjectionPermissionDialogComponent);return i;}

frameworks/base/core/res/res/values/config.xml

<string name="config_mediaProjectionPermissionDialogComponent" translatable="false">com.android.systemui/com.android.systemui.media.MediaProjectionPermissionActivity</string>

frameworks/base/packages/SystemUI/AndroidManifest.xml

            <!-- started from MediaProjectionManager --><activityandroid:name=".media.MediaProjectionPermissionActivity"android:exported="true"android:theme="@style/Theme.SystemUI.MediaProjectionAlertDialog"android:finishOnCloseSystemDialogs="true"android:launchMode="singleTop"android:excludeFromRecents="true"android:visibleToInstantApps="true"/>

MediaProjectionPermissionActivity 就是弹窗的主体

frameworks/base/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java

   @Overridepublic void onCreate(Bundle icicle) {super.onCreate(icicle);mPackageName = getCallingPackage();IBinder b = ServiceManager.getService(MEDIA_PROJECTION_SERVICE);mService = IMediaProjectionManager.Stub.asInterface(b);if (mPackageName == null) {finish();return;}PackageManager packageManager = getPackageManager();ApplicationInfo aInfo;try {aInfo = packageManager.getApplicationInfo(mPackageName, 0);mUid = aInfo.uid;} catch (PackageManager.NameNotFoundException e) {Log.e(TAG, "unable to look up package name", e);finish();return;}try {if (mService.hasProjectionPermission(mUid, mPackageName)) {setResult(RESULT_OK, getMediaProjectionIntent(mUid, mPackageName));finish();return;}} catch (RemoteException e) {Log.e(TAG, "Error checking projection permissions", e);finish();return;}TextPaint paint = new TextPaint();paint.setTextSize(42);CharSequence dialogText = null;CharSequence dialogTitle = null;if (Utils.isHeadlessRemoteDisplayProvider(packageManager, mPackageName)) {dialogText = getString(R.string.media_projection_dialog_service_text);dialogTitle = getString(R.string.media_projection_dialog_service_title);} else {String label = aInfo.loadLabel(packageManager).toString();// If the label contains new line characters it may push the security// message below the fold of the dialog. Labels shouldn't have new line// characters anyways, so just truncate the message the first time one// is seen.final int labelLength = label.length();int offset = 0;while (offset < labelLength) {final int codePoint = label.codePointAt(offset);final int type = Character.getType(codePoint);if (type == Character.LINE_SEPARATOR|| type == Character.CONTROL|| type == Character.PARAGRAPH_SEPARATOR) {label = label.substring(0, offset) + ELLIPSIS;break;}offset += Character.charCount(codePoint);}if (label.isEmpty()) {label = mPackageName;}String unsanitizedAppName = TextUtils.ellipsize(label,paint, MAX_APP_NAME_SIZE_PX, TextUtils.TruncateAt.END).toString();String appName = BidiFormatter.getInstance().unicodeWrap(unsanitizedAppName);String actionText = getString(R.string.media_projection_dialog_text, appName);SpannableString message = new SpannableString(actionText);int appNameIndex = actionText.indexOf(appName);if (appNameIndex >= 0) {message.setSpan(new StyleSpan(Typeface.BOLD),appNameIndex, appNameIndex + appName.length(), 0);}dialogText = message;dialogTitle = getString(R.string.media_projection_dialog_title, appName);}View dialogTitleView = View.inflate(this, R.layout.media_projection_dialog_title, null);TextView titleText = (TextView) dialogTitleView.findViewById(R.id.dialog_title);titleText.setText(dialogTitle);mDialog = new AlertDialog.Builder(this).setCustomTitle(dialogTitleView).setMessage(dialogText).setPositiveButton(R.string.media_projection_action_text, this).setNegativeButton(android.R.string.cancel, this).setOnCancelListener(this).create();mDialog.create();mDialog.getButton(DialogInterface.BUTTON_POSITIVE).setFilterTouchesWhenObscured(true);final Window w = mDialog.getWindow();w.setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);w.addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);mDialog.show();}private Intent getMediaProjectionIntent(int uid, String packageName)throws RemoteException {IMediaProjection projection = mService.createProjection(uid, packageName,MediaProjectionManager.TYPE_SCREEN_CAPTURE, false /* permanentGrant */);Intent intent = new Intent();intent.putExtra(MediaProjectionManager.EXTRA_MEDIA_PROJECTION, projection.asBinder());return intent;}
  1. 申请成功后返回结果给到申请的Activity:
    getMediaProjectionIntent函数中, 创建了IMediaProjection并通过Intent返回给了调用的App

    setResult(RESULT_OK, getMediaProjectionIntent(mUid, mPackageName));
    
    IMediaProjection projection = mService.createProjection(uid, packageName,MediaProjectionManager.TYPE_SCREEN_CAPTURE, false /* permanentGrant */);Intent intent = new Intent();intent.putExtra(MediaProjectionManager.EXTRA_MEDIA_PROJECTION, projection.asBinder());getMediaProjection(resultCode, data)
    
  2. Activity 调用 getMediaProjection 获取MediaProjection

frameworks/base/media/java/android/media/projection/MediaProjectionManager.java

  public MediaProjection getMediaProjection(int resultCode, @NonNull Intent resultData) {if (resultCode != Activity.RESULT_OK || resultData == null) {return null;}IBinder projection = resultData.getIBinderExtra(EXTRA_MEDIA_PROJECTION);if (projection == null) {return null;}return new MediaProjection(mContext, IMediaProjection.Stub.asInterface(projection));}

总的来说, 这个流程稍微绕了一点路:

App MediaProjectionManager SystemUI MediaProjectionService createScreenCaptureIntent MediaProjectionPermissionActivity createProjection onActivityResult getMediaProjection App MediaProjectionManager SystemUI MediaProjectionService

createProjection的实现

frameworks/base/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java

         @Override // Binder callpublic IMediaProjection createProjection(int uid, String packageName, int type,boolean isPermanentGrant) {if (mContext.checkCallingPermission(Manifest.permission.MANAGE_MEDIA_PROJECTION)!= PackageManager.PERMISSION_GRANTED) {throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION in order to grant "+ "projection permission");}if (packageName == null || packageName.isEmpty()) {throw new IllegalArgumentException("package name must not be empty");}final UserHandle callingUser = Binder.getCallingUserHandle();long callingToken = Binder.clearCallingIdentity();MediaProjection projection;try {ApplicationInfo ai;try {ai = mPackageManager.getApplicationInfoAsUser(packageName, 0, callingUser);} catch (NameNotFoundException e) {throw new IllegalArgumentException("No package matching :" + packageName);}projection = new MediaProjection(type, uid, packageName, ai.targetSdkVersion,ai.isPrivilegedApp());if (isPermanentGrant) {mAppOps.setMode(AppOpsManager.OP_PROJECT_MEDIA,projection.uid, projection.packageName, AppOpsManager.MODE_ALLOWED);}} finally {Binder.restoreCallingIdentity(callingToken);}return projection;}

通过反射, 调用MediaProjectionService的createProjection


注意: 此方法需要有系统权限(android.uid.system)

    //android.os.ServiceManager;static Object getService(String name){try {Class ServiceManager = Class.forName("android.os.ServiceManager");Method getService = ServiceManager.getDeclaredMethod("getService", String.class);return getService.invoke(null, name);} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}return null;}@SuppressLint("SoonBlockedPrivateApi")static Object asInterface(Object binder){try {Class IMediaProjectionManager_Stub = Class.forName("android.media.projection.IMediaProjectionManager$Stub");Method asInterface = IMediaProjectionManager_Stub.getDeclaredMethod("asInterface", IBinder.class);return asInterface.invoke(null, binder);} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}return null;}//    private IMediaProjectionManager mService;//android.media.projection.IMediaProjectionManager@SuppressLint("SoonBlockedPrivateApi")public static MediaProjection createProjection(){//Context.java public static final String MEDIA_PROJECTION_SERVICE = "media_projection";//IBinder b = ServiceManager.getService(MEDIA_PROJECTION_SERVICE);//        mService = IMediaProjectionManager.Stub.asInterface(b);IBinder b = (IBinder) getService("media_projection");Object mService = asInterface(b) ;//IMediaProjection projection = mService.createProjection(uid, packageName,//MediaProjectionManager.TYPE_SCREEN_CAPTURE, false /* permanentGrant */);//public static final int TYPE_SCREEN_CAPTURE = 0;try {Logger.i("createProjection", "createProjection");Class IMediaProjectionManager = Class.forName("android.media.projection.IMediaProjectionManager");// public IMediaProjection createProjection(int uid, String packageName, int type, boolean isPermanentGrant)Method createProjection = IMediaProjectionManager.getDeclaredMethod("createProjection", Integer.TYPE, String.class, Integer.TYPE, Boolean.TYPE);Object projection = createProjection.invoke(mService, android.os.Process.myUid(), App.getApp().getPackageName(),0, false);Logger.i("createProjection", "projection created!");//android.media.projection.IMediaProjection;Class IMediaProjection = IInterface.class;//Class.forName("android.media.projection.IMediaProjection");Method asBinder = IMediaProjection.getDeclaredMethod("asBinder");Logger.i("createProjection", "asBinder found");Intent intent = new Intent();//    public static final String EXTRA_MEDIA_PROJECTION =//            "android.media.projection.extra.EXTRA_MEDIA_PROJECTION";//Bundle extra = new Bundle();//extra.putBinder("android.media.projection.extra.EXTRA_MEDIA_PROJECTION",  (IBinder)asBinder.invoke(projection));//intent.putExtra("android.media.projection.extra.EXTRA_MEDIA_PROJECTION",  (IBinder)asBinder.invoke(projection));intent.putExtra(Intent.EXTRA_RETURN_RESULT, Activity.RESULT_OK);Object projBinder = asBinder.invoke(projection);Logger.i("createProjection", "asBinder invoke success.");//intent.getExtras().putBinder("android.media.projection.extra.EXTRA_MEDIA_PROJECTION",  (IBinder)projBinder);Method putExtra = Intent.class.getDeclaredMethod("putExtra", String.class, IBinder.class);putExtra.invoke(intent, "android.media.projection.extra.EXTRA_MEDIA_PROJECTION",  (IBinder)projBinder);Logger.i("createProjection", "putExtra with IBinder success.");MediaProjectionManager projMgr = App.getApp().getMediaProjectionManager();MediaProjection mp = projMgr.getMediaProjection(Activity.RESULT_OK, intent);Logger.i("createProjection", "getMediaProjection " + (mp == null ? " Failed" : "Success"));//new MediaProjection(mContext, IMediaProjection.Stub.asInterface(projection));//if(mp != null)mp.stop();return  mp;} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}return null;}

参考

Android截屏录屏MediaProjection分享
Android录屏的三种方案
媒体投影
[Android] 使用MediaProjection截屏
android设备间实现无线投屏

相关文章:

Android 调用系统服务接口获取屏幕投影(需要android.uid.system)

媒体投影 借助 Android 5&#xff08;API 级别 21&#xff09;中引入的 android.media.projection API&#xff0c;您可以将设备屏幕中的内容截取为可播放、录制或投屏到其他设备&#xff08;如电视&#xff09;的媒体流。 Android 14&#xff08;API 级别 34&#xff09;引入…...

Node.js - Express框架

1. 介绍 Express 是一个基于 Node.js 的 Web 应用程序框架&#xff0c;主要用于快速、简便地构建 Web 应用程序 和 API。它是目前最流行的 Node.js Web 框架之一&#xff0c;具有轻量级、灵活和功能丰富的特点。 核心概念包括路由&#xff0c;中间件&#xff0c;请求与响应&a…...

Picocli 命令行框架

官方文档 https://picocli.info/ 官方提供的快速入门教程 https://picocli.info/quick-guide.html 使用 Picocli 创建命令行应用程序 Picocli 是一个用于构建 Java 命令行应用的强大框架&#xff0c;它简化了参数解析和帮助消息生成的过程。 下面是如何使用 Picocli 构建简单命…...

Vscode——SSH连接不上的一种解决办法

一、完整报错: > @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ > IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY! > Someone could be eavesdropping on you right now (man-in-the...

Stream流

一 : Stream流的介绍 stream不存储数据&#xff0c;而是按照特定的规则对数据进行计算&#xff0c;一般会输出结果&#xff1b; stream不会改变数据源&#xff0c;通常情况下会产生一个新的集合&#xff1b; stream具有延迟执行特性&#xff0c;只有调用终端操作时&#xff…...

开源文件存储分享平台Seafile部署与应用

Seafile 是一款开源的企业云盘,注重可靠性和性能,支持全平台客户端。Seafile 内置协同文档 SeaDoc ,让协作撰写、管理和发布文档更便捷。适用于团队协作、文件存储和同步的开源解决方案,它提供了可靠、安全和易用的云存储服务。主要有以下特点: 文件存储和同步:Seafile 允…...

RAG技术:是将知识库的文档和问题共同输入到LLM中

RAG技术 RAG技术是将知识库的文档和问题共同输入到LLM中 RAG技术是先从知识库中检索出与问题相关的文档片段,然后将这些检索到的文档片段与问题一起输入到LLM中进行回答。具体过程如下: 文本分块 由于LLM的上下文窗口有限,需要将长文本资料分割成较小的块,以便LLM能够有…...

战略与规划方法——深入解析波士顿矩阵(BCG Matrix):分析产品组合的关键工具

深入解析波士顿矩阵(BCG Matrix):分析产品组合的关键工具 在现代商业管理中,合理地分析和管理产品组合对于企业的成功至关重要。波士顿矩阵(BCG Matrix),又称为成长份额矩阵,是一种由波士顿咨询集团(Boston Consulting Group)在20世纪70年代提出的战略工具,用于帮助…...

GORM(Go语言数据交互库)

GORM&#xff08;Go ORM&#xff0c;即对象关系映射&#xff09;是Go语言中非常流行且功能强大的数据库交互库。它简化了与关系型数据库的交互过程&#xff0c;提供了丰富的API来处理各种数据库操作。下面将详细介绍GORM的功能、使用方法和一些高级特性。 1. 安装 首先&#…...

Spring Boot教程之五十七:在 Apache Kafka 上发布 JSON 消息

Spring Boot | 如何在 Apache Kafka 上发布 JSON 消息 Apache Kafka是一个发布-订阅消息系统。消息队列允许您在进程、应用程序和服务器之间发送消息。在本文中&#xff0c;我们将了解如何在 Spring Boot 应用程序中向 Apache Kafka 发送 JSON 消息。 为了了解如何创建 Spring…...

开发指南091-延迟退休算法

公布平台上人力资源系统有关延迟退休算法&#xff1a; package org.qlm.util;public class busiUtil {/*birthYearMonth 出生年月 yyyy-MMmode 0 男职工 1 女干部 2 女职工*/public static String calculateRetirementDate(String birthYearMonth, String mode){if ("0&…...

Flask-SQLAlchemy 基于一个base表 - 动态创建使用相同字段的其他业务表

1 安装 首先&#xff0c;确保您安装了 Flask 和 SQLAlchemy&#xff0c;以及 MySQL 的驱动程序&#xff08;例如 mysql-connector-python 或 PyMySQL&#xff09;&#xff1a; pip install Flask Flask-SQLAlchemy mysql-connector-python2 创建项目结构 创建一个简单的项目…...

数据结构--二叉树

目录 有序二叉树&#xff1a; 平衡二叉树&#xff1a; 234树&#xff1a; 红黑树 红黑树特点&#xff1a; 为什么红黑树是最优二叉树&#xff1f; 哈夫曼树和哈夫曼编码 有序二叉树&#xff1a; 平衡二叉树&#xff1a; 在有序二叉树的基础上得来的&#xff0c;且左右子…...

【编译构建】用cmake编译libjpeg动态库并实现转灰度图片

先编译出libjepg动态库 1、下载libjpeg源码: https://github.com/libjpeg-turbo/libjpeg-turbo 2、编译出动态库或静态库 写一个编译脚本&#xff0c;用cmake构建。 #!/bin/bash# 定义变量 SOURCE_DIR"/home/user/libjpeg-turbo-main" BUILD_DIR"${SOURCE_…...

vLLM私有化部署大语言模型LLM

目录 一、vLLM介绍 二、安装vLLM 1、安装环境 2、安装步骤 三、运行vLLM 1、运行方式 2、切换模型下载源 3、运行本地已下载模型 四、通过http访问vLLM 一、vLLM介绍 vLLM&#xff08;官方网址&#xff1a;https://www.vllm.ai&#xff09;是一种用于大规模语言模型&#x…...

人工智能任务19-基于BERT、ELMO模型对诈骗信息文本进行识别与应用

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下人工智能任务19-基于BERT、ELMO模型对诈骗信息文本进行识别与应用。近日&#xff0c;演员王星因接到一份看似来自知名公司的拍戏邀约&#xff0c;被骗至泰国并最终被带到缅甸。这一事件迅速引发了社会的广泛关注。该…...

ESP-IDF学习记录(5) 画一块esp32-c3 PCB板

最近看了半个多月&#xff0c;趁着嘉立创官方活动&#xff0c;研究esp32-c3规格书&#xff0c;白嫖PCB 和元器件。原本计划按照官方推荐的搞个四层板&#xff0c;结果打样太贵&#xff0c;火速改成双层板&#xff0c;用了官方的券。小于10*10,也可以使用嘉立创的免费打样。 下面…...

Day04-后端Web基础——Maven基础

目录 Maven课程内容1. Maven初识1.1 什么是Maven?1.2 Maven的作用1.2.1 依赖管理1.2.2 项目构建1.2.3 统一项目结构 2. Maven概述2.1 Maven介绍2.2 Maven模型2.2.1 构建生命周期/阶段(Build lifecycle & phases)2.2.2 项目对象模型 (Project Object Model)2.2.3 依赖管理模…...

ASP.NET Core - 日志记录系统(一)

ASP.NET Core - 日志记录系统&#xff08;一&#xff09; 一、日志记录二、ASP.Net Core 的日志记录2.1. 日志记录系统的接入2.2 记录日志2.3 基本配置2.3.1 日志级别2.3.2 全局输出配置2.3.3 针对特定日志提供程序的配置2.3.6 显式设置2.3.4 配置筛选原理2.3.5 日志作用域 一、…...

Linux 各个服务启动命令

目录 redis后台启动rocketMq后台启动mongodb后台启动mysql后台启动 redis后台启动 ./redis-server ./redis.confrocketMq后台启动 #关闭Nameserver sh bin/mqshutdown namesrv #关闭Broker sh bin/mqshutdown broker #启动namesrv nohup sh bin/mqnamesrv -n 127.0.0.1:9876 …...

24-25-1-单片机开卷部分习题和评分标准

依据相关规定试卷必须按评分标准进行批改。 给分一定是宽松的&#xff0c;能给分一定给&#xff0c;如有疑问也可以向学院教务办申请查卷。 一部分学生期末成绩由于紧张或其他原因导致分数过低&#xff0c;也是非常非常遗憾的。 个人也是非常抱歉的。 开卷考试 简答题 第一…...

Apache Hop从入门到精通 第二课 Apache Hop 核心概念/术语

1、apache hop核心概念思维导图 虽然apache hop是kettle的一个分支&#xff0c;但是它的概念和kettle还是有一些区别的&#xff0c;下图是我根据官方文档梳理的appache hop的核心概念思维导图。 2、Tools&#xff08;工具&#xff09; 1&#xff09;Hop Conf Hop Conf 是一个…...

网络安全 | Web安全常见漏洞和防护经验策略

关注&#xff1a;CodingTechWork 引言 OWASP (Open Web Application Security Project) Top 10是Web应用最常见的安全风险集合&#xff0c;帮助开发人员和安全专家识别和防止最严重的网络安全问题。以下是基于OWASP Top 10的Web安全防护经验策略与规则集。Web开发者必须对潜在…...

Unity 3D游戏开发从入门进阶到高级

本文精心整理了Unity3D游戏开发相关的学习资料&#xff0c;涵盖入门、进阶、性能优化、面试和书籍等多个维度&#xff0c;旨在为Unity开发者提供全方位、高含金量的学习指南.欢迎收藏。 学习社区 Unity3D开发者 这是一个专注于Unity引擎的开发者社区&#xff0c;汇聚了众多Un…...

浅谈云计算14 | 云存储技术

云存储技术 一、云计算网络存储技术基础1.1 网络存储的基本概念1.2云存储系统结构模型1.1.1 存储层1.1.2 基础管理层1.1.3 应用接口层1.1.4 访问层 1.2 网络存储技术分类 二、云计算网络存储技术特点2.1 超大规模与高可扩展性2.1.1 存储规模优势2.1.2 动态扩展机制 2.2 高可用性…...

No.1|Godot|俄罗斯方块复刻|棋盘和初始方块的设置

删掉基础图标新建assets、scenes、scripts文件夹 俄罗斯方块的每种方块都是由四个小方块组成的&#xff0c;很适合放在网格地图中 比如网格地图是宽10列&#xff0c;高20行 要实现网格的对齐和下落 Node2D节点 新建一个Node2D 添加2个TileMapLayer 一个命名为Board&…...

二 RK3568 固件中打开 ADB 调试

一 usb adb Android 系统,设置->开发者选项->已连接到计算机 打开,usb调试开关打开 通过 usb otg 口连接 开发上位机 (windows/linux) 上位机安装 adb 服务之后 , 通过 cmd/shell: #1 枚举设备 adb devices #2 进入 android shell adb shell # 3 验证上传下载…...

鸿蒙报错Init keystore failed: keystore password was incorrect

报错如下&#xff1a; > hvigor ERROR: Failed :entry:defaultSignHap... > hvigor ERROR: Tools execution failed. 01-13 16:35:55 ERROR - hap-sign-tool: error: Init keystore failed: keystore password was incorrect * Try the following: > The key stor…...

Java学习笔记(二十三)

1 CacheEvict CacheEvict是Spring框架中用于清空缓存的注解。以下是对CacheEvict注解的详细介绍&#xff1a; 1.1 作用 CacheEvict注解的主要作用是删除缓存中的数据。在方法执行后或执行前&#xff08;根据配置&#xff09;&#xff0c;它可以清空指定的缓存项或整个缓存区…...

TIOBE编程语言排行靠前的编程语言的吉祥物

Python的吉祥物&#xff1a;小蟒蛇 Python语言的吉祥物是一只名叫"Pythonidae"&#xff08;或简称"Py"&#xff09;的小蟒蛇。这个吉祥物由Tobias Kohn设计于2005年&#xff0c;它的形象借鉴了真实的蟒蛇&#xff0c;但加入了一些可爱和友善的特点。小蟒蛇…...

Redis集群部署详解:主从复制、Sentinel哨兵模式与Cluster集群的工作原理与配置

集群部署形式 1、主从复制1.1 工作机制1.2 配置实现1.3 优缺点1.4 部署形式1.5 主从复制优化 2、Sentinel 哨兵模式2.1 工作机制2.2 配置实现2.3 优缺点2.4 哨兵机制选举流程2.5 脑裂问题解决方案 3、Redis Cluster3.1 工作机制3.2 配置实现3.3 优缺点3.4 故障转移3.5 哈希槽为…...

Dubbo泛化调用

本文记录下利用dubbo泛化调用实现网关server收http请求&#xff0c;然后转发给dubbo服务&#xff0c;然后收到dubbo响应的功能原理。 关键点1&#xff1a;dubbo泛化调用。可根据(注册中心地址、接口名&#xff0c;方法名&#xff0c;参数类型&#xff09;唯一确定一个dubbo服务…...

SpringBoot工程快速启动

1.问题导入 以后我们和前端开发人员协同开发&#xff0c;而前端开发人员需要测试前端程序就需要后端开启服务器&#xff0c;这就受制于后端开发人员。 为了摆脱这个受制&#xff0c;前端开发人员尝试着在自己电脑上安装 Tomcat 和 Idea &#xff0c;在自己电脑上启动后端程序&a…...

Docker实践:部署Docker管理工具DockerUI

Docker实践&#xff1a;部署Docker管理工具DockerUI 前言一、DockerUI介绍1.1 DockerUI概述1.2 镜像说明 二、检查本地Docker环境三、拉取DockerUI镜像四、创建DockerUI容器五、访问DockerUI六、DockerUI的基本使用6.1 查询宿主机容器情况6.2 查询Docker镜像列表6.3 查看容器配…...

【优先算法】滑动窗口--(结合例题讲解解题思路)(C++)

目录 1. 例题1&#xff1a;最大连续1的个数 1.1 解题思路 1.2代码实现 1.3 错误示范如下&#xff1a;我最开始写了一种&#xff0c;但是解答错误&#xff0c;请看&#xff0c;给大家做个参考 2. 将 x 减到 0 的最小操作数 2.1解题思路 2.2代码实现 1. 例题1&#xff…...

嵌入式系统Linux实时化(四)Xenomai应用开发测试

1、Xenomai 原生API 任务管理 Xenomai 本身提供的一系列多任务调度机制,主要有以下一些函数: int rt_task_create (RT_TASK task, const char name, int stksize, int prio, intmode) ; 任务的创建;int rt_task_start(RT_TASK task, void(entry)(void cookie), void cookie…...

深度剖析RabbitMQ:从基础组件到管理页面详解

文章目录 一、简介二、Overview2.1 Overview->Totals2.2 Overview->Nodesbroker的属性2.3 Overview->Churn statistics2.4 Overview->Ports and contexts2.5 Overview->Export definitions2.6 Overview->Import definitions 三、Connections连接的属性 四、C…...

算法每日双题精讲 —— 二分查找(二分查找,在排序数组中查找元素的第一个和最后一个位置)

&#x1f31f;快来参与讨论&#x1f4ac;&#xff0c;点赞&#x1f44d;、收藏⭐、分享&#x1f4e4;&#xff0c;共创活力社区。 &#x1f31f; 别再犹豫了&#xff01;快来订阅我们的算法每日双题精讲专栏&#xff0c;一起踏上算法学习的精彩之旅吧&#xff01;&#x1f4aa…...

Golang—— error 和 panic

本文详细介绍Golang的两种错误处理机制&#xff1a;error 和 panic。 文章目录 Golang 的错误处理机制概述error特点代码示例基本用法创建 error panic特点运行时错误示例defer 和 recover 的结合使用代码示例基本用法创建 panic panic 的执行机制 error 和 panic 的对比生产环…...

xcrun: error: invalid active developer path 解决

在拉取 github 代码时&#xff0c;提示如下报错&#xff1a; xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun 原因是&#xff1a;这是由于 Xcode command line t…...

Jmeter配置服务代理器 Proxy(二)

1.创建脚本记录器 2.配置&#xff1a;Jmeter代理、端口、记录目标等 3.配置谷歌浏览器代理 浏览器配置代理的详细教程可参考&#xff1a;使用whistle代理-CSDN博客 4.启动Jmeter记录器 点击ok后弹出这个界面&#xff0c;生成了证书&#xff1a; 5.给浏览器安装Jmeter代理的证书…...

小黑工具人日常积累中:sqlserver中切割字符串,取首个子串

SELECTSUBSTRING(表名字, 1, CHARINDEX(分隔符, 字段名) - 1) AS FirstPart FROM表名字 WHERECHARINDEX(分隔符, 字段名) > 0继续尝试: 提取第二个子串 窗口函数...

港科夜闻 | 香港科大与微软亚洲研究院签署战略合作备忘录,推动医学健康教育及科研协作...

关注并星标 每周阅读港科夜闻 建立新视野 开启新思维 1、香港科大与微软亚洲研究院签署战略合作备忘录&#xff0c;推动医学健康教育及科研协作。根据备忘录&#xff0c;双方将结合各自于科研领域的优势&#xff0c;携手推动医学健康领域的交流与合作。合作方向将涵盖人才培训、…...

掌握Golang strings包:高效字符串处理指南

掌握Golang strings包&#xff1a;高效字符串处理指南 引言为什么要学习和掌握strings包本教程的目标 基本用法strings包概述导入strings包常用函数列表及简要介绍 字符串创建与基本操作创建字符串字符串连接&#xff1a;Join重复字符串&#xff1a;Repeat修改字符串&#xff1…...

关于husky8.0 与 4.0的配置

husky的场景使用很多&#xff0c;一般大多场景是在配置git commit 命令拦截hook, 校验 commit-msg 格式规范。以下环境默认&#xff1a;git > 2.27.0, node >14 1、安装huskey8.0.1 npm install --save-dev husky8.0.1 2、初始化配置文件 在package.json scripts 属性…...

【RK3588 Linux 5.x 内核编程】-Linux内核数据结构详解(双向链表、基数树、位数组)

Linux内核数据结构详解(双向链表、基数树、位数组) 文章目录 Linux内核数据结构详解(双向链表、基数树、位数组)1、双向链表2、基数树3、位数组3.1 Linux内核中的位数组和位操作3.2 位数组声明3.3 特定于架构的位操作3.4 常见的位操作Linux内核提供了不同的数据结构实现,如…...

3.Qt Quick-QML地图引擎之v4.3版本(新增动态轨迹线/海图/天地图街道/天地图卫星)

在上个版本Qt Quick-QML地图引擎之v4版本(新增多模型切换/3D模型欧拉角模拟)_qt加载3d地图-CSDN博客更新了3D模拟功能&#xff0c;在4.3版本增加动态轨迹线、三个地图(海图/天地图街道/天地图卫星)。 4.3版本已经支持qt6 cmake版本&#xff0c;而4.3版本以下支持qt5版本&#x…...

使用WebdriverIO和Appium测试App

1.新建项目 打开Webstorm新建项目 打开终端输入命令 npm init -y npm install wdio/cli allure-commandline --save-dev npx wdio config 然后在终端依次选择如下&#xff1a; 然后在终端输入命令&#xff1a; npm install wdio/local-runnerlatest wdio/mocha-frameworkla…...

前端组件开发:组件开发 / 定义配置 / 配置驱动开发 / 爬虫配置 / 组件V2.0 / form表单 / table表单

一、最早的灵感 最早的灵感来自sprider / 网络爬虫 / 爬虫配置&#xff0c;在爬虫爬取网站文章时候&#xff0c;会输入给爬虫一个配置文件&#xff0c;里边的内容是一个json对象。里边包含了所有想要抓取的页面的信息。爬虫通过这个配置就可以抓取目标网站的数据。其实本文要引…...

工具推荐:PDFgear——免费且强大的PDF编辑工具 v2.1.12

PDFgear——免费且强大的PDF编辑工具 v2.1.12 软件简介 PDFgear 是一款 完全免费的 PDF 软件&#xff0c;支持 阅读、编辑、转换、合并 以及 跨设备签署 PDF 文件&#xff0c;无需注册即可使用。它提供了丰富的 PDF 处理功能&#xff0c;极大提升了 PDF 文件管理的便捷性和效…...