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

Android13系统源码内置App并通过AIDL调用获取内置存储卡的真实大小

jix 进行从事Android系统源码开发不得不在原有的系统上内置自己的App。通过内置App一般都需要调用些系统才能访问的系统级App。App的部署和调试需要依赖源码系统。通过命令 : mm 来实现。

第三方App想调用内置的app需要通过跨进程调用。

这里通过AIDL来实现跨进程调用。

首先声明AIDL文件,

Android源码工程的文件构成和格式和标准的app完全不一样。

为了方便调试,先在标准的App中调试通过。

再copy标准工程到源码App工程里。

声明的AIDL文件:

Callback.aidl

package com.android.kvservice;interface Callback {oneway void onMessageReceived(int type, String value);
}

KvInterface.aidl

package com.android.kvservice;import com.android.kvservice.Callback;interface KvInterface {void registerCallback(Callback callback);void unregisterCallback(Callback callback);void sendMessage(int type, String value);
}

AIDL的文件夹放的位置

注意在build.gradle 里声明: aidl true

plugins {alias(libs.plugins.androidApplication)alias(libs.plugins.jetbrainsKotlinAndroid)
}android {namespace 'com.yyy.xxx.service'compileSdk 34defaultConfig {applicationId "com.yyy.xxx.kvservice"minSdk 29targetSdk 34versionCode 1versionName "1.0"testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"vectorDrawables {useSupportLibrary true}}buildTypes {release {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'}}compileOptions {sourceCompatibility JavaVersion.VERSION_1_8targetCompatibility JavaVersion.VERSION_1_8}kotlinOptions {jvmTarget = '1.8'}buildFeatures {compose trueviewBinding trueaidl true}composeOptions {kotlinCompilerExtensionVersion '1.5.1'}packaging {resources {excludes += '/META-INF/{AL2.0,LGPL2.1}'}}}dependencies {implementation libs.androidx.core.ktximplementation libs.androidx.lifecycle.runtime.ktximplementation libs.androidx.activity.composeimplementation platform(libs.androidx.compose.bom)implementation libs.androidx.uiimplementation libs.androidx.ui.graphicsimplementation libs.androidx.ui.tooling.previewimplementation libs.androidx.material3testImplementation libs.junitandroidTestImplementation libs.androidx.junitandroidTestImplementation libs.androidx.espresso.coreandroidTestImplementation platform(libs.androidx.compose.bom)androidTestImplementation libs.androidx.ui.test.junit4debugImplementation libs.androidx.ui.toolingdebugImplementation libs.androidx.ui.test.manifest
}

实现AIDL接口的地方

import android.content.Context;
import android.os.Binder;
import android.os.Build;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.StatFs;
import android.os.storage.StorageVolume;
import android.util.Log;
import android.os.storage.DiskInfo;
import android.os.storage.VolumeInfo;
import android.os.storage.StorageManager;
import android.app.usage.StorageStatsManager;import com.android.kvservice.Callback;
import com.android.kvservice.KvInterface;
import com.android.server.kvservice.storage.StorageEntry;
import com.android.server.kvservice.storage.StorageUtils;import java.util.List;public class KVService extends KvInterface.Stub {/*** 获取系统全部内存大小,包括隐藏的内存*/
//    public static final int GET_SYSTEM_STORGE_TOTAL = 1;public static final int GET_ALL_STORGE = 1;/****/public static final int GET_SYSTEM_STORGE_REMAIN = 2;public static final int GET_SDCARD_TOTAL = 3;public static final int GET_SDCARD_REMAIN = 4;private static final String TAG = KVService.class.getSimpleName();private RemoteCallbackList<Callback> mCallbackList = new RemoteCallbackList<>();private Context mContext;private Object lack = new Object();private StorageManager storageManager = null;public KVService(Context context) {this.mContext = context;storageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);Log.d(TAG, "henryservice init");}@Overridepublic void registerCallback(Callback callback) {boolean result = mCallbackList.register(callback);Log.d(TAG, "register pid:" + Binder.getCallingPid()+ " uid:" + Binder.getCallingUid() + " result:" + result);}@Overridepublic void unregisterCallback(Callback callback) {boolean result = mCallbackList.unregister(callback);Log.d(TAG, "unregister pid:" + Binder.getCallingPid()+ " uid:" + Binder.getCallingUid() + " result:" + result);}@Overridepublic void sendMessage(int type, String value) throws RemoteException {String result = new String("no-data");if (type == GET_ALL_STORGE) {
//           ....}Log.e(TAG, "rev the type : =========== " + type);Log.e(TAG, "rev the value : =========== " + value);sendEventToRemote(type, result);}public void sendEventToRemote(int type, String value) {synchronized (lack) {int count = mCallbackList.getRegisteredCallbackCount();Log.d(TAG, "remote callback count:" + count);if (count > 0) {// 注意: 遍历过程如果存在多线程操作, 需要加锁, 不然可能会抛出异常final int size = mCallbackList.beginBroadcast();for (int i = 0; i < size; i++) {Callback cb = mCallbackList.getBroadcastItem(i);try {if (cb != null) {cb.onMessageReceived(type, value);}} catch (RemoteException e) {e.printStackTrace();Log.d(TAG, "remote exception:" + e.getMessage());}}mCallbackList.finishBroadcast();}}}}

实现Service的地方:

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;import androidx.annotation.Nullable;import com.android.kvservice.Callback;
import com.android.kvservice.KvInterface;
import com.android.server.kvservice.KVService;public class KService extends Service {private KVService kvService = null;@Overridepublic void onCreate() {super.onCreate();if (kvService == null) {kvService = new KVService(this);}}@Nullable@Overridepublic IBinder onBind(Intent intent) {return binder;}private final KvInterface.Stub binder = new KvInterface.Stub() {@Overridepublic void registerCallback(Callback callback) throws RemoteException {Log.e("KService", " registerCallback ============ ");kvService.registerCallback(callback);Log.e("KService", " registerCallback ============ end");}@Overridepublic void unregisterCallback(Callback callback) throws RemoteException {Log.e("KService", " unregisterCallback ============ ");kvService.unregisterCallback(callback);Log.e("KService", " unregisterCallback ============ end");}@Overridepublic void sendMessage(int type, String value) throws RemoteException {kvService.sendMessage(type, value);Log.e("KService", " sendMessage ============ end");}};
}

本地调用Service的代码。


import android.app.Activity;
import android.app.Service;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.widget.Button;import androidx.annotation.Nullable;import com.android.kvservice.Callback;
import com.android.kvservice.KvInterface;
import com.android.server.kvservice.KVService;public class MainActivity extends Activity {//    private MainBinding binding;private KvInterface kvInterface;private Button btnStart;@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);
//        binding = MainBinding.inflate(getLayoutInflater());
//        setContentView(binding.getRoot());setContentView(R.layout.main);btnStart = findViewById(R.id.btnStart);btnStart.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (kvInterface == null) {bindToService();}}});Button btnSend = findViewById(R.id.btnSend);btnSend.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Log.e("TAG", "send 111");registerCallback();if (kvInterface != null) {try {Log.e("TAG", "send 222");kvInterface.sendMessage(1, "");} catch (RemoteException e) {e.printStackTrace();}}}});}private boolean register = false;private Callback.Stub callback = new Callback.Stub() {@Overridepublic void onMessageReceived(int type, String value) throws RemoteException {Log.e("MainActivity", "rev the type:: ==== " + type);Log.e("MainActivity", "rev the value:: ==== " + value);}};private void registerCallback() {if (!register) {register = true;try {if (kvInterface != null) {kvInterface.registerCallback(callback);}} catch (Exception e) {e.printStackTrace();}}}@Overrideprotected void onDestroy() {super.onDestroy();try {if (kvInterface != null) {kvInterface.unregisterCallback(callback);}} catch (RemoteException e) {throw new RuntimeException(e);}}private ServiceConnection serviceConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {kvInterface = KvInterface.Stub.asInterface(service);}@Overridepublic void onServiceDisconnected(ComponentName name) {kvInterface = null;}};private void bindToService() {
//        bindService(new Intent("com.kingview.qti.service.KService"), serviceConnection, Service.BIND_AUTO_CREATE);bindService(new Intent(this, KService.class), serviceConnection, Service.BIND_AUTO_CREATE);Log.e("TAG","bindToService ======================");}
}

为了第三方App调用,需要再配置文件中做以下声明:

  <serviceandroid:name="com.kingview.qti.service.KService"android:enabled="true"android:exported="true"android:process="com.kingview.qti.service.kservice"><intent-filter><action android:name="com.kingview.service.kservice" /></intent-filter></service>

第三方App调用AIDL服务的代码,发现调用Action并没有什么用,特别注意要输入完整的包名:

  private fun bindToService() {val intent = Intent()intent.setComponent(ComponentName("com.kingview.qti.service","com.kingview.qti.service.KService"))bindService(intent,serviceConnection,BIND_AUTO_CREATE)
//        Log.e("StorageTestActivity", " bindToService ====================== ")}

注册远程回调

 private fun registerCallback() {if (!register) {register = truetry {if (kvInterface != null) {kvInterface!!.registerCallback(callback)}kvInterface?.sendMessage(1, "")} catch (e: Exception) {e.printStackTrace()}}}

反注册callback和 解绑Service。

override fun onDestroy() {super.onDestroy()kvInterface?.unregisterCallback(callback)unbindService(serviceConnection)}

监听实现的操作是这样实现的:

 @Volatileprivate var register = falseprivate val callback: Callback = object : Callback.Stub() {@Throws(RemoteException::class)override fun onMessageReceived(type: Int, value: String) {Log.e("StorageTestActivity", "rev the type:: ==== $type")Log.e("StorageTestActivity", "rev the value:: ==== $value")//解析数据,并显示到界面上if (testKey == KVApplication.TEST_STORAGE) {val strs = value.split("#").filter { v ->v.trim() != ""}for (v in strs) {val bean = Gson().fromJson<StorageBean>(v, StorageBean::class.java)if (bean.description.contains("internal_storage")) {val total = bean.total.toLong() / 1000f / 1000f / 1000f;val used = bean.used.toLong() / 1000f / 1000f / 1000f;val remain = total - usedbinding.txtStatus.post {binding.txtSize.text = " Size: ${total} GB ; Remain ${remain} GB. \n "}}}}}}

通过以上操作你可能会发现,依然无法调用远程的Service。你需要再AndroidManifest里声明一个权限。

 <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"tools:ignore="QueryAllPackagesPermission" />

将App放置在源码工程的的 package/apps/里创建一个文件夹如:XYZService

src/ res/ Androidmanifast.xml 都要从标准App工程里copy出来。

 Android.bp这样写,包含了AIDL文件 :

//
// Copyright (C) 2013 Google Inc.
//package {default_applicable_licenses: ["packages_apps_kvservice_license"],
}// Added automatically by a large-scale-change
// See: http://go/android-license-faq
license {name: "packages_apps_kvservice_license",visibility: [":__subpackages__"],license_kinds: ["SPDX-license-identifier-BSD",],// large-scale-change unable to identify any license_text files
}android_app {name: "XYZServiceTest",defaults: ["platform_app_defaults"],platform_apis: true,certificate: "platform",system_ext_specific: true,privileged: true,srcs: ["src/**/*.java","src/**/*.aidl",],aidl: {local_include_dirs: ["src/aidl"],},manifest: "AndroidManifest.xml",resource_dirs: ["res",],// privileged: true,// sdk_version: "33",// sdk_version: "current",// certificate: "platform",// platform_apis: true,// product_specific: true,static_libs: ["androidx.core_core",// "androidx.annotation:annotation:1.3.0","guava",],
}

 通过阅读Setting源码移植的代码如下:

    public static List<StorageEntry> getAllStorageEntries(Context context,StorageManager storageManager) {final List<StorageEntry> storageEntries = new ArrayList<>();storageEntries.addAll(storageManager.getVolumes().stream().filter(volumeInfo -> isStorageSettingsInterestedVolume(volumeInfo)).map(volumeInfo -> new StorageEntry(context, volumeInfo)).collect(Collectors.toList()));storageEntries.addAll(storageManager.getDisks().stream().filter(disk -> isDiskUnsupported(disk)).map(disk -> new StorageEntry(disk)).collect(Collectors.toList()));storageEntries.addAll(storageManager.getVolumeRecords().stream().filter(volumeRecord -> isVolumeRecordMissed(storageManager, volumeRecord)).map(volumeRecord -> new StorageEntry(volumeRecord)).collect(Collectors.toList()));return storageEntries;}

public class StorageEntry implements Comparable<StorageEntry>, Parcelable  {private final VolumeInfo mVolumeInfo;private final DiskInfo mUnsupportedDiskInfo;private final VolumeRecord mMissingVolumeRecord;private final String mVolumeInfoDescription;public StorageEntry(@NonNull Context context, @NonNull VolumeInfo volumeInfo) {mVolumeInfo = volumeInfo;mUnsupportedDiskInfo = null;mMissingVolumeRecord = null;if (isDefaultInternalStorage()) {// Shows "This device" for default internal storage.mVolumeInfoDescription = "storage_default_internal_storage";} else {mVolumeInfoDescription = context.getSystemService(StorageManager.class).getBestVolumeDescription(mVolumeInfo);}}public StorageEntry(@NonNull DiskInfo diskInfo) {mVolumeInfo = null;mUnsupportedDiskInfo = diskInfo;mMissingVolumeRecord = null;mVolumeInfoDescription = null;}public StorageEntry(@NonNull VolumeRecord volumeRecord) {mVolumeInfo = null;mUnsupportedDiskInfo = null;mMissingVolumeRecord = volumeRecord;mVolumeInfoDescription = null;}private StorageEntry(Parcel in) {mVolumeInfo = in.readParcelable(VolumeInfo.class.getClassLoader());mUnsupportedDiskInfo = in.readParcelable(DiskInfo.class.getClassLoader());mMissingVolumeRecord = in.readParcelable(VolumeRecord.class.getClassLoader());mVolumeInfoDescription = in.readString();}@Overridepublic int describeContents() {return 0;}@Overridepublic void writeToParcel(Parcel out, int flags) {out.writeParcelable(mVolumeInfo, 0 /* parcelableFlags */);out.writeParcelable(mUnsupportedDiskInfo, 0 /* parcelableFlags */);out.writeParcelable(mMissingVolumeRecord, 0 /* parcelableFlags */);out.writeString(mVolumeInfoDescription);}public static final Parcelable.Creator<StorageEntry> CREATOR =new Parcelable.Creator<StorageEntry>() {public StorageEntry createFromParcel(Parcel in) {return new StorageEntry(in);}public StorageEntry[] newArray(int size) {return new StorageEntry[size];}};@Overridepublic boolean equals(Object o) {if (o == this) {return true;}if (!(o instanceof StorageEntry)) {return false;}final StorageEntry StorageEntry = (StorageEntry) o;if (isVolumeInfo()) {return mVolumeInfo.equals(StorageEntry.mVolumeInfo);}if (isDiskInfoUnsupported()) {return mUnsupportedDiskInfo.equals(StorageEntry.mUnsupportedDiskInfo);}return mMissingVolumeRecord.equals(StorageEntry.mMissingVolumeRecord);}@Overridepublic int hashCode() {if (isVolumeInfo()) {return mVolumeInfo.hashCode();}if (isDiskInfoUnsupported()) {return mUnsupportedDiskInfo.hashCode();}return mMissingVolumeRecord.hashCode();}@Overridepublic String toString() {if (isVolumeInfo()) {return mVolumeInfo.toString();}if (isDiskInfoUnsupported()) {return mUnsupportedDiskInfo.toString();}return mMissingVolumeRecord.toString();}@Overridepublic int compareTo(StorageEntry other) {if (isDefaultInternalStorage() && !other.isDefaultInternalStorage()) {return -1;}if (!isDefaultInternalStorage() && other.isDefaultInternalStorage()) {return 1;}if (isVolumeInfo() && !other.isVolumeInfo()) {return -1;}if (!isVolumeInfo() && other.isVolumeInfo()) {return 1;}if (isPrivate() && !other.isPrivate()) {return -1;}if (!isPrivate() && other.isPrivate()) {return 1;}if (isMounted() && !other.isMounted()) {return -1;}if (!isMounted() && other.isMounted()) {return 1;}if (!isVolumeRecordMissed() && other.isVolumeRecordMissed()) {return -1;}if (isVolumeRecordMissed() && !other.isVolumeRecordMissed()) {return 1;}if (getDescription() == null) {return 1;}if (other.getDescription() == null) {return -1;}return getDescription().compareTo(other.getDescription());}/*** Returns default internal storage.*/public static StorageEntry getDefaultInternalStorageEntry(Context context) {return new StorageEntry(context, context.getSystemService(StorageManager.class).findVolumeById(VolumeInfo.ID_PRIVATE_INTERNAL));}/*** If it's a VolumeInfo.*/public boolean isVolumeInfo() {return mVolumeInfo != null;}/*** If it's an unsupported DiskInfo.*/public boolean isDiskInfoUnsupported() {return mUnsupportedDiskInfo != null;}/*** If it's a missing VolumeRecord.*/public boolean isVolumeRecordMissed() {return mMissingVolumeRecord != null;}/*** If it's a default internal storage.*/public boolean isDefaultInternalStorage() {if (isVolumeInfo()) {return mVolumeInfo.getType() == VolumeInfo.TYPE_PRIVATE&& TextUtils.equals(mVolumeInfo.getId(), VolumeInfo.ID_PRIVATE_INTERNAL);}return false;}/*** If it's a mounted storage.*/public boolean isMounted() {return mVolumeInfo == null ? false : (mVolumeInfo.getState() == VolumeInfo.STATE_MOUNTED|| mVolumeInfo.getState() == VolumeInfo.STATE_MOUNTED_READ_ONLY);}/*** If it's an unmounted storage.*/public boolean isUnmounted() {return mVolumeInfo == null ? false : (mVolumeInfo.getState() == VolumeInfo.STATE_UNMOUNTED);}/*** If it's an unmountable storage.*/public boolean isUnmountable() {return mVolumeInfo == null ? false : mVolumeInfo.getState() == VolumeInfo.STATE_UNMOUNTABLE;}/*** If it's a private storage.*/public boolean isPrivate() {return mVolumeInfo == null ? false : mVolumeInfo.getType() == VolumeInfo.TYPE_PRIVATE;}/*** If it's a public storage.*/public boolean isPublic() {return mVolumeInfo == null ? false : mVolumeInfo.getType() == VolumeInfo.TYPE_PUBLIC;}/*** Returns description.*/public String getDescription() {if (isVolumeInfo()) {return mVolumeInfoDescription;}if (isDiskInfoUnsupported()) {return mUnsupportedDiskInfo.getDescription();}return mMissingVolumeRecord.getNickname();}/*** Returns ID.*/public String getId() {if (isVolumeInfo()) {return mVolumeInfo.getId();}if (isDiskInfoUnsupported()) {return mUnsupportedDiskInfo.getId();}return mMissingVolumeRecord.getFsUuid();}/*** Returns disk ID.*/public String getDiskId() {if (isVolumeInfo()) {return mVolumeInfo.getDiskId();}if (isDiskInfoUnsupported()) {return mUnsupportedDiskInfo.getId();}return null;}/*** Returns fsUuid.*/public String getFsUuid() {if (isVolumeInfo()) {return mVolumeInfo.getFsUuid();}if (isDiskInfoUnsupported()) {return null;}return mMissingVolumeRecord.getFsUuid();}/*** Returns root file if it's a VolumeInfo.*/public File getPath() {return mVolumeInfo == null ? null : mVolumeInfo.getPath();}/*** Returns VolumeInfo of the StorageEntry.*/public VolumeInfo getVolumeInfo() {return mVolumeInfo;}
}

Setting关于计算存储卡的代码在

StorageUsageProgressBarPreferenceController 

StorageDashboardFragment文件

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • EmbeddedGUI简介
  • 语音控制开关的语音识别ic芯片方案
  • Linux信号处理机制基础
  • 创新之光闪耀,点赋科技在第十三届创新创业大赛中绽放光彩
  • BaseCTF Week2
  • linux固定ip
  • Tampermonkey 安装
  • Python的8个构建桌面应用的技巧
  • CNN网络的一些基本知识
  • 代码随想录算法训练营day58:图论08:拓扑排序精讲;dijkstra(朴素版)精讲
  • [C++进阶]map和set的相关题目
  • 数据结构-c/c++实现栈(详解,栈容量可以动态增长)
  • MySQL——基础操作
  • 【Unity】简单机甲运动系统——坦克式操控方式
  • 房产报备小程序房产报备系统源码搭建方案
  • 【翻译】Mashape是如何管理15000个API和微服务的(三)
  • Angularjs之国际化
  • ECMAScript6(0):ES6简明参考手册
  • JAVA 学习IO流
  • java8-模拟hadoop
  • Promise面试题,控制异步流程
  • python大佬养成计划----difflib模块
  • ReactNative开发常用的三方模块
  • Redis 懒删除(lazy free)简史
  • Unix命令
  • Vue ES6 Jade Scss Webpack Gulp
  • Webpack 4 学习01(基础配置)
  • 发布国内首个无服务器容器服务,运维效率从未如此高效
  • 服务器从安装到部署全过程(二)
  • 技术胖1-4季视频复习— (看视频笔记)
  • 简析gRPC client 连接管理
  • 漫谈开发设计中的一些“原则”及“设计哲学”
  • 让你的分享飞起来——极光推出社会化分享组件
  • 时间复杂度与空间复杂度分析
  • 使用agvtool更改app version/build
  • 推荐一个React的管理后台框架
  • 在Mac OS X上安装 Ruby运行环境
  • 【云吞铺子】性能抖动剖析(二)
  • ​如何使用ArcGIS Pro制作渐变河流效果
  • ​学习一下,什么是预包装食品?​
  • #Java第九次作业--输入输出流和文件操作
  • (4)事件处理——(6)给.ready()回调函数传递一个参数(Passing an argument to the .ready() callback)...
  • (Arcgis)Python编程批量将HDF5文件转换为TIFF格式并应用地理转换和投影信息
  • (BFS)hdoj2377-Bus Pass
  • (第27天)Oracle 数据泵转换分区表
  • (二)测试工具
  • (附源码)计算机毕业设计SSM基于java的云顶博客系统
  • (十二)springboot实战——SSE服务推送事件案例实现
  • (数据结构)顺序表的定义
  • (原)本想说脏话,奈何已放下
  • (转)母版页和相对路径
  • .mat 文件的加载与创建 矩阵变图像? ∈ Matlab 使用笔记
  • .NET 4.0中的泛型协变和反变
  • .NET C# 操作Neo4j图数据库
  • .net CHARTING图表控件下载地址