AndroidP HIDL 转载

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/sinat_18179367/article/details/95940030

Android P HAL层添加HIDL实例

本文是参照 https://www.jianshu.com/p/b80865c61d8e 教程介绍实现,原理请参考原作者。

本文将介绍如何在P OS上添加HIDL详细实现过程,简单增加seLinux策略使得可以在system_service调用测试,并用模拟器emulator验证。

调用过程为 APP->TestManager->TestService->ITest.hal

实现过程

一 、hardware部分

1.1 编写 .hal

.hal的语言格式是C++和Java的结合体。

在 AOSP代码目录 hardware/interfaces/test/1.0/

新建 types.hal (非必要,用于定义结构体,复杂变量可在此定义)

//types.hal
package android.hardware.test@1.0;

struct TestID{
int32_t id;
string name;
};

struct TestEvent{
int32_t what;
string msg;
};

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

新建ITestCallback.hal (非必要,用于回调使用)

//ITestCallback.hal
package android.hardware.test@1.0;

interface ITestCallback {
oneway onTestEvent(TestEvent event);
};

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

新建 ITest.hal (主接口)

//ITest.hal
package android.hardware.test@1.0;

interface ITest {
init(TestID id);
//无返回值
helloWorld(string name) generates (string result);
//变量类型string 不是String
setCallback(ITestCallback callback) generates (bool res);
//变量类型bool 不是boolean
release();
};

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
1.2 使用hidl-gen生成变量

使用hidl-gen的前提是AOSP全编通过,如果之前全编通过可不用再次全编

source ./build/envsetup.sh
lunch aosp_car_x86_64-eng
make -j4
make hidl-gen -j4

 
 
 
 
  • 1
  • 2
  • 3
  • 4

设置临时变量

PACKAGE=android.hardware.test@1.0
LOC=hardware/interfaces/test/1.0/default

 
 
 
 
  • 1
  • 2

使用hidl-gen生成default目录 里的C++文件

hidl-gen -o $LOC -Lc++-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport $PACKAGE

 
 
 
 
  • 1

使用hidl-gen生成default目录 里的Android.bp文件

hidl-gen -o $LOC -Landroidbp-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport $PACKAGE

 
 
 
 
  • 1

使用update-makefiles.sh生成1.0目录下的Android.bp

./hardware/interfaces/update-makefiles.sh

 
 
 
 
  • 1

在default目录创建

此时的目录结构为

├── 1.0
│   ├── default
│   │   ├── Android.bp
│   │   ├── Test.cpp
│   │   ├── Test.h
│   │   ├── TestCallback.cpp
│   │   └── TestCallback.h
│   ├── Android.bp
│   ├── ITest.hal
│   ├── ITestCallback.hal
│   └── types.hal

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

TestCallback.cpp和 TestCallback.h没用删掉,并修改default里的Android.bp 删掉TestCallback.cpp

1.3 实现.cpp
Test.h (由hidl-gen工具生成)

line 35 注释打开就是使用passthrough模式

#ifndef ANDROID_HARDWARE_TEST_V1_0_TEST_H
#define ANDROID_HARDWARE_TEST_V1_0_TEST_H

#include <android/hardware/test/1.0/ITest.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
#include <utils/Thread.h>

namespace android {
namespace hardware {
namespace test {
namespace V1_0 {
namespace implementation {

using ::android::hardware::hidl_array;
using ::android::hardware::hidl_memory;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::sp;

struct Test : public ITest , public Thread{
// Methods from ::android::hardware::test::V1_0::ITest follow.
Return<void> init(const ::android::hardware::test::V1_0::TestID& id) override;
Return<void> helloWorld(const hidl_string& name, helloWorld_cb _hidl_cb) override;
Return<bool> setCallback(const sp<::android::hardware::test::V1_0::ITestCallback>& callback) override;
Return<void> release() override;

// Methods from ::android::hidl::base::V1_0::IBase follow.
virtual bool threadLoop();

};

// FIXME: most likely delete, this is only for passthrough implementations
// extern “C” ITest* HIDL_FETCH_ITest(const char* name);

} // namespace implementation
} // namespace V1_0
} // namespace test
} // namespace hardware
} // namespace android

#endif // ANDROID_HARDWARE_TEST_V1_0_TEST_H

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
Test.cpp (由hidl-gen工具生成)

简单实现各个方法

#define LOG_TAG "Test_cpp"
#include "Test.h"
#include <log/log.h>

namespace android {
namespace hardware {
namespace test {
namespace V1_0 {
namespace implementation {

pthread_t pthread;
sp<ITestCallback> mCallback = nullptr;
std::string mName;
int32_t mID;
bool mExit;

// Methods from ::android::hardware::test::V1_0::ITest follow.
Return<void> Test::init(const ::android::hardware::test::V1_0::TestID& id) {
mExit = false;
mName = id.name;
mID = id.id;
ALOGD(“init:”);
run(“test_thread”);
return Void();
}

Return<void> Test::helloWorld(const hidl_string& name, helloWorld_cb _hidl_cb) {
ALOGD(“helloWorld:”);
char buf[100];
::memset(buf,0x00,100);
::snprintf(buf,100,“Hello World,%s”,name.c_str());
hidl_string result(buf);

_hidl_cb(result);
return Void();

}

Return<bool> Test::setCallback(const sp<::android::hardware::test::V1_0::ITestCallback>& callback) {
mCallback = callback;
bool res = false;
if(mCallback != nullptr) {
ALOGD(“setCallback: done”);
res = true;
}
return res;
}

Return<void> Test::release() {
mExit = true;
ALOGD(“release:”);
return Void();
}

bool Test::threadLoop(){
static int32_t count = 0;
TestEvent event;
while(!mExit) {
::sleep(1);
event.msg = mName;
event.what = count ++;
if(mCallback != nullptr) {
mCallback->onTestEvent(event);
}
}
ALOGD(“threadLoop: exit”);
return false;
}

// Methods from ::android::hidl::base::V1_0::IBase follow.

//ITest* HIDL_FETCH_ITest(const char* /* name */) {
//return new Test();
//}
//
} // namespace implementation
} // namespace V1_0
} // namespace test
} // namespace hardware
} // namespace android

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
添加启动service

新建android.hardware.test@1.0-service.rc 启动脚本

service test_hal_service /vendor/bin/hw/android.hardware.test@1.0-service
    class hal
    user system
    group syste

 
 
 
 
  • 1
  • 2
  • 3
  • 4

新建service.cpp 这里使用绑定式 直通式为注释部分

#define LOG_TAG "android.hardware.test@1.0-service"
#include <android-base/logging.h>
#include <hidl/HidlTransportSupport.h>
#include <android/hardware/test/1.0/ITest.h>

#include <hidl/LegacySupport.h>
#include “Test.h”
using android::hardware::configureRpcThreadpool;
using android::hardware::joinRpcThreadpool;
using android::hardware::test::V1_0::implementation::test;
//using android::hardware::defaultPassthroughServiceImplementation;
//passthrough mode

int main() {
configureRpcThreadpool(4, true);

Test test;
auto status = test.registerAsService();
CHECK_EQ(status, android::OK) &lt;&lt; "Failed to register test HAL implementation";

joinRpcThreadpool();
return 0;  // joinRpcThreadpool shouldn't exit

// return defaultPassthroughServiceImplementation<ITest>();
//passthrough mode
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

修改Android.bp

cc_binary {
    name: "android.hardware.test@1.0-service",
    relative_install_path: "hw",
    defaults: ["hidl_defaults"],
    proprietary: true,
    init_rc: ["android.hardware.test@1.0-service.rc"],
    srcs: [
		   "Test.cpp",
	       "service.cpp",
	      ],
    shared_libs: [
		"libbase",      
        "liblog",
        "libdl",
        "libutils",
        "libhardware",
        "libhidlbase",
        "libhidltransport",
        "android.hardware.test@1.0",
    ],
}

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

调用 update-makefiles.sh更新一下

当前目录结构为

├── 1.0
│   ├── default
│   │   ├── Android.bp
│   │   ├── Test.cpp
│   │   ├── Test.h
│   │   ├── android.hardware.test@1.0-service.rc
│   │   └── service.cpp
│   ├── Android.bp
│   ├── ITest.hal
│   ├── ITestCallback.hal
│   └── types.hal

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

单编试一下 ,出错请检查代码请参考附录解决办法。

mmm ./hardware/interfaces/test/1.0

 
 
 
 
  • 1

[外链图片转存失败(img-pGZeVrJ7-1563157041998)(C:\Users\GW00175635\AppData\Roaming\Typora\typora-user-images\1562749332399.png)]

1.4 VNDK相关

在目录aosp\build\make\target\product\vndk 里

28.txt 和 current.txt 按照字母顺序新增

VNDK-core: android.hardware.test@1.0.so

 
 
 
 
  • 1

二、device部分

由于此次要使用emulator验证,并且lunch的是aosp_car_x86_64-eng

所以在device找到下面目录aosp\device\generic\car\common\manifest.xml

其他device要在对应的目录找到manifest

在manifest.xml添加

	<hal format="hidl">
        <name>android.hardware.test</name>
        <transport>hwbinder</transport>
        <version>1.0</version>
        <interface>
            <name>ITest</name>
            <instance>default</instance>
        </interface>
    </hal>

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在car.mk添加 启动 test service

# Auto modules
PRODUCT_PACKAGES += \
   ……
	android.hardware.test@1.0-service

 
 
 
 
  • 1
  • 2
  • 3
  • 4

三、SELinux部分——hal service

9.0上Android 安全策略再次加强,hal service需要修改selinux配置

lunch为 aosp_car_x86_64-eng 对应的car device目录下没有BoardConfig.mk,也没有对应的sepolicy

所以只能修改系统的sepolicy

目录为aosp\system\sepolicy

该目录下有vendor public private(注意public 下的修改同样也要修改到prebuilts\api\28.0 下的对应文件,否则编译会报错) 位置找不到参考audiocontrol的位置 或者比较熟悉的hal模块

3.1 vendor 目录

file_contexts 添加

/(vendor|system/vendor)/bin/hw/android\.hardware\.test@1\.0-service          u:object_r:hal_test_default_exec:s0
  • 1
  • 2

新建 hal_test_default.te

type hal_test_default, domain;
hal_server_domain(hal_test_default, hal_test)

type hal_test_default_exec, exec_type, vendor_file_type, file_type;
init_daemon_domain(hal_test_default)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
3.2 public 目录

attributes 添加

hal_attribute(test);

 
 
 
 
  • 1

hwservice.te 添加

type hal_test_hwservice, hwservice_manager_type;

 
 
 
 
  • 1

新建 hal_test.te

# HwBinder IPC from client to server, and callbacks
binder_call(hal_test_client, hal_test_server)
binder_call(hal_test_server, hal_test_client)

add_hwservice(hal_test_server, hal_test_hwservice)

allow hal_test_client hal_test_hwservice:hwservice_manager find;

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

将以上修改同步到aosp\system\sepolicy\prebuilts\api\28.0\public

3.3 private 目录

hwservice_contexts 添加

android.hardware.test::ITest                                    u:object_r:hal_test_hwservice:s0

 
 
 
 
  • 1

private/compat/26.0/26.0.ignore.cil 添加

hal_test_hwservice

 
 
 
 
  • 1

private/compat/27.0/27.0.ignore.cil 添加

hal_test_hwservice

 
 
 
 
  • 1

将以上修改同步到aosp\system\sepolicy\prebuilts\api\28.0\private

四 、客户端实现

4.1 system_service 实现
4.1.1 TestManager端

在目录aosp\frameworks\base\core\java\android\os里 新建test目录

创建ITestService.aidl 对应hal层 四个功能

// ITestManager.aidl
package android.os.test;

import android.os.test.ITestEventListener;
// Declare any non-default types here with import statements

interface ITestService {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/

void init(int id,String name);
String helloWorld(String str);
boolean setTestEventListener(ITestEventListener listener);
void release();

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

创建ITestEventListener.aidl ITestService.aidl 里传递的自定类

// ITestEventListener.aidl
package android.os.test;
import android.os.test.TestListenerEvent;
// Declare any non-default types here with import statements

interface ITestEventListener {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/

void onEvent (inout TestListenerEvent event);
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

创建ITestEvent.aidl ITestEventListener.aidl 里传递的 event 类型变量

// ITestEvent.aidl
package android.os.test;

// Declare any non-default types here with import statements

parcelable TestListenerEvent;

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

创建TestListerEvent.java

package android.os.test;

import android.os.Parcel;
import android.os.Parcelable;

/**

  • android.os.test.TestListenerEvent

  • @author GW00175635

  • @date 2019/7/11
    */
    public class TestListenerEvent implements Parcelable {
    private int what;
    private String msg;

    public TestListenerEvent(int what, String msg) {
    this.what = what;
    this.msg = msg;
    }

    public TestListenerEvent(Parcel in) {
    what = in.readInt();
    msg = in.readString();
    }

    public void setWhat(int what) {
    this.what = what;
    }

    public void setMsg(String msg) {
    this.msg = msg;
    }

    public int getWhat() {

     <span class="token keyword">return</span> what<span class="token punctuation">;</span>
    

    }

    public String getMsg() {
    return msg;
    }

    public static final Creator<TestListenerEvent> CREATOR = new Creator<TestListenerEvent>() {
    @Override
    public TestListenerEvent createFromParcel(Parcel in) {
    return new TestListenerEvent(in);
    }

     <span class="token annotation punctuation">@Override</span>
     <span class="token keyword">public</span> TestListenerEvent<span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token function">newArray</span><span class="token punctuation">(</span><span class="token keyword">int</span> size<span class="token punctuation">)</span> <span class="token punctuation">{</span>
         <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">TestListenerEvent</span><span class="token punctuation">[</span>size<span class="token punctuation">]</span><span class="token punctuation">;</span>
     <span class="token punctuation">}</span>
    

    };

    @Override
    public int describeContents() {
    return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
    dest.writeInt(what);
    dest.writeString(msg);
    }

    /**

    • <p>从parcel中读取,从parcel中读取,顺序与write一致</p>
    • 如果要支持为 out 或者 inout 的定向 tag 的话,需要实现 readFromParcel() 方法
    • @param dest
      */
      public void readFromParcel(Parcel dest) {
      what = dest.readInt();
      msg = dest.readString();
      }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78

创建TestManager.java 供上层APP调用的TestManager

package android.os.test;

/**

  • android.os.test.TestManager;
  • @author GW00175635
  • @date 2019/7/11
    */

import android.os.RemoteException;
import android.util.Log;

public class TestManager {
private ITestService mService;
public static final String TAG = “TestManager”;

<span class="token keyword">public</span> <span class="token function">TestManager</span><span class="token punctuation">(</span>ITestService server<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    Log<span class="token punctuation">.</span><span class="token function">d</span><span class="token punctuation">(</span>TAG<span class="token punctuation">,</span> <span class="token string">"TestManager: "</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    mService <span class="token operator">=</span> server<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">init</span><span class="token punctuation">(</span><span class="token keyword">int</span> id<span class="token punctuation">,</span>String name<span class="token punctuation">)</span><span class="token punctuation">{</span>
    Log<span class="token punctuation">.</span><span class="token function">d</span><span class="token punctuation">(</span>TAG<span class="token punctuation">,</span> <span class="token string">"init: "</span><span class="token operator">+</span>id<span class="token operator">+</span><span class="token string">" "</span><span class="token operator">+</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">try</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>mService <span class="token operator">!=</span> null<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            mService<span class="token punctuation">.</span><span class="token function">init</span><span class="token punctuation">(</span>id<span class="token punctuation">,</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">RemoteException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">public</span> String <span class="token function">helloWorld</span><span class="token punctuation">(</span>String str<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    Log<span class="token punctuation">.</span><span class="token function">d</span><span class="token punctuation">(</span>TAG<span class="token punctuation">,</span> <span class="token string">"helloWorld: "</span><span class="token operator">+</span>str<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">try</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>mService <span class="token operator">==</span> null<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">return</span> null<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">return</span> mService<span class="token punctuation">.</span><span class="token function">helloWorld</span><span class="token punctuation">(</span>str<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">RemoteException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">return</span> <span class="token string">"service connect failed"</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">setTestListener</span><span class="token punctuation">(</span>TestEventListener listener<span class="token punctuation">)</span><span class="token punctuation">{</span>
    Log<span class="token punctuation">.</span><span class="token function">d</span><span class="token punctuation">(</span>TAG<span class="token punctuation">,</span> <span class="token string">"setTestListener: "</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">try</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>mService <span class="token operator">==</span> null<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">return</span>  mService<span class="token punctuation">.</span><span class="token function">setTestEventListener</span><span class="token punctuation">(</span>listener<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">RemoteException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">release</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    Log<span class="token punctuation">.</span><span class="token function">d</span><span class="token punctuation">(</span>TAG<span class="token punctuation">,</span> <span class="token string">"release: "</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">try</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span><span class="token punctuation">(</span>mService <span class="token operator">!=</span> null<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            mService<span class="token punctuation">.</span><span class="token function">release</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">RemoteException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
package android.os.test;

/**

  • android.os.test
  • GW00175635
  • 2019/7/13
    */
    public abstract class TestEventListener extends ITestEventListener.Stub {

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

在aosp\frameworks\base\Android.bp里添加

		"core/java/android/os/test/ITestEventListener.aidl",
		"core/java/android/os/test/TestListenerEvent.aidl",
		"core/java/android/os/test/ITestService.aidl",

 
 
 
 
  • 1
  • 2
  • 3
4.1.2 TestService端

在目录 aosp\frameworks\base\services\core

Android.bp添加test独有类的引用

    static_libs: [
        ……
		"android.hardware.test-V1.0-java",
        ……
    ],

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5

在目录 aosp\frameworks\base\services\core\java\com\android\server\test

新建TestService.java

package com.android.server.test;

import android.hardware.test.V1_0.ITest;
import android.hardware.test.V1_0.ITestCallback;
import android.hardware.test.V1_0.TestEvent;
import android.hardware.test.V1_0.TestID;
import android.os.RemoteException;
import android.util.Log;

import android.os.test.ITestEventListener;
import android.os.test.ITestService;
import android.os.test.TestListenerEvent;

import java.util.ArrayList;

/**

  • com.android.server.test.TestService

  • @author GW00175635

  • @date 2019/7/11
    */
    public class TestService extends ITestService.Stub {
    private String TAG = “TestService”;
    private ITest halService ;
    public TestService(){
    try {
    halService = ITest.getService();//获取service
    } catch (RemoteException e) {
    e.printStackTrace();
    }
    }
    @Override
    public void init(int id, String name) throws RemoteException {
    Log.d(TAG, "init: ");
    TestID testID = new TestID();
    testID.id = id;
    testID.name = name;
    halService.init(testID);
    }

    @Override
    public String helloWorld(String str) throws RemoteException {
    Log.d(TAG, "helloWorld: ");
    return halService.helloWorld(str);
    }

    @Override
    public boolean setTestEventListener(ITestEventListener listener) throws RemoteException {
    Log.d(TAG, "setTestEventListener: ");
    TestCallback testCallback = new TestCallback(listener);
    return halService.setCallback(testCallback);
    }

    @Override
    public void release() throws RemoteException {
    Log.d(TAG, "release: ");
    halService.release();
    }

    class TestCallback extends ITestCallback.Stub{
    ITestEventListener mITestEventListener;
    TestCallback (ITestEventListener listener){
    mITestEventListener = listener;
    }
    @Override
    public void onTestEvent(TestEvent testEvent) throws RemoteException {
    Log.d(TAG, "onTestEvent: ");
    TestListenerEvent testListenerEvent = new TestListenerEvent(testEvent.what,testEvent.msg);
    mITestEventListener.onEvent(testListenerEvent);
    }
    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76

在目录aosp\frameworks\base\core\java\android\content\Context.java里添加

	/**
     * {@link android.os.TestManager} for receiving intents at a
     * time of your choosing.
     *
     * @see #getSystemService
     * @see android.os.TestManager
     */
    public static final String TEST_SERVICE = "test";

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在目录aosp\frameworks\base\core\java\android\app

SystemServiceRegistry.java 里添加

import android.os.test.TestManager;
import android.os.test.ITestService;
        ……
		registerService(Context.TEST_SERVICE, TestManager.class,
                new CachedServiceFetcher<TestManager>() {
            @Override
            public HelloManager createService(ContextImpl ctx) {
                IBinder iBinder = ServiceManager.getService(Context.TEST_SERVICE);
                if (iBinder == null) {
                    return null;
                }
                ITestService service = ITestService.Stub
                        .asInterface(iBinder);
                return new TestManager(service);
            }});
        ……
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

在目录aosp\frameworks\base\services\java\com\android\server

SystemServer.java 添加

import com.android.server.test.TestService;
    private void startOtherServices(){
			……
			try {
				Slog.i(TAG, "test Service");
				ServiceManager.addService(Context.TEST_SERVICE, new TestService());
			} catch (Throwable e) {
				reportWtf("starting TestService", e);
			}
			……
	}		
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
4.1.3 添加selinux策略
public 目录

service.te添加

type test_service, system_api_service, system_server_service, service_manager_type;

 
 
 
 
  • 1

将以上修改同步到aosp\system\sepolicy\prebuilts\api\28.0\public

private 目录

service_contexts 添加 和Context 保持一致 TEST_SERVICE = “test”;

test									  u:object_r:test_service:s0

 
 
 
 
  • 1

system_server.te 添加

hal_client_domain(system_server, hal_test)

 
 
 
 
  • 1

private/compat/26.0/26.0.ignore.cil 添加

test_service

 
 
 
 
  • 1

private/compat/27.0/27.0.ignore.cil 添加

test_service

 
 
 
 
  • 1

将以上修改同步到aosp\system\sepolicy\prebuilts\api\28.0\private

4.2 APP实现调用
4.2.1 APP调用TestManager

在目录aosp\packages\apps\TestAPP下新建

res src 文件夹 src放代码 res放资源 建议在Android studio里编写后复制相关文件到此目录

TestManager可以在Android studio里写个测试用的。

package com.gwm.testapp;

import android.app.Activity;

import android.content.Context;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.test.TestManager;
import android.os.test.TestEventListener;
import android.os.test.TestListenerEvent;
import android.view.View;
import android.widget.Button;
import android.util.Log;

/**

  • GW00175635
    */
    public class MainActivity extends Activity {
    TestManager mTestManager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mTestManager = (TestManager)getSystemService(Context.TEST_SERVICE);
    Button init = findViewById(R.id.button_init);
    Button hello = findViewById(R.id.button_hello);
    Button set = findViewById(R.id.button_setCallback);
    Button release = findViewById(R.id.button_release);
    init.setOnClickListener(mOnClickListener);
    hello.setOnClickListener(mOnClickListener);
    set.setOnClickListener(mOnClickListener);
    release.setOnClickListener(mOnClickListener);

    }

    View.OnClickListener mOnClickListener = new View.OnClickListener() {
    @Override
    public void onClick(View view) {
    switch (view.getId()){
    case R.id.button_init:
    mTestManager.init(123,“name=testAPP”);
    break;
    case R.id.button_hello:
    String res = mTestManager.helloWorld(“HelloFromTestAPP”);
    Log.d(“activity”,res);
    break;
    case R.id.button_setCallback:
    mTestManager.setTestListener(new TestEventListener(){
    @Override
    public void onEvent(TestListenerEvent event) {
    String msg = event.getMsg();
    int what = event.getWhat();
    Log.d(“activity”,msg+" "+what);
    }
    });
    break;
    case R.id.button_release:
    mTestManager.release();
    break;
    default:
    break;
    }
    }
    };

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
4.2.2编写make文件
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_CERTIFICATE := platform
LOCAL_MODULE_TAGS := eng
LOCAL_PACKAGE_NAME := TestApp
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PRIVATE_PLATFORM_APIS := true
include $(BUILD_PACKAGE)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

最后代码目录为

[外链失败(img-dAojhx0f-1563157041999)(C:\Users\GW00175635\AppData\Roaming\Typora\typora-user-images\1562919352977.png)]

五、启动模拟器验证

5.1 替换镜像文件到SDK下

因为改动了系统API,所以在全编之前 执行 make update-api 更新下 API

再执行make 命令

全编之后,在产物目录aosp\out\target\product\generic_x86_64复制以下文件

替换到SDK目录C:\AndroidSDK\system-images\android-28\default\x86_64 里(如果没有该镜像目录,先在AVDManager里下载28 x86_64的镜像)

system-qemu.img 和 vendor-qemu.img 删掉qemu

复制产物目录的data文件夹到SDK目录替换

复制产物目录的system\build.prop 到SDK目录替换

在windows平台使用Android studio自带的AVDmanager 启动emulator。

在这里插入图片描述

5.2 启动emulator

在这里插入图片描述
选个分辨率差不多的
在这里插入图片描述

选择刚才替换的镜像
在这里插入图片描述

起一个好记的名字

[外链图片转存失败(img-yU6RCOTj-1563157042001)(C:\Users\GW00175635\AppData\Roaming\Typora\typora-user-images\1563150895465.png)]

使用AVDmanager启动
在这里插入图片描述
在这里插入图片描述

5.3 ADB调试

使用CMD命令

在SDK的emulator文件夹目录下

C:\AndroidSDK\emulator>emulator -avd Car0715 -writable-system

[外链图片转存失败(img-lFDeDpwF-1563157042002)(C:\Users\GW00175635\AppData\Roaming\Typora\typora-user-images\1563151545546.png)]

启动avd并让其system可写。

另起一个cmd命令框,就可以有写权限的使用ADB命令

[外链图片转存失败(img-uLuyZeSo-1563157042002)(C:\Users\GW00175635\AppData\Roaming\Typora\typora-user-images\1563152632699.png)]

附录——错误处理

1.语法错误,结构体少加分号 ;

root@BDJS-PF1LR28T:~/workspace/aosp# hidl-gen -o $LOC -Lc++-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport $PACKAGE
ERROR: missing ; at /mnt/f/ubuntu_win/aosp/hardware/interfaces/test/1.0/types.hal:7.2-1
ERROR: missing ; at /mnt/f/ubuntu_win/aosp/hardware/interfaces/test/1.0/types.hal:12.2-1
hidl-gen F 07-10 11:01:06 30277 30277 Coordinator.cpp:213] Check failed: ret == nullptr
Aborted (core dumped)

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5

2.语法错误,忘记import ITestCallbak

root@BDJS-PF1LR28T:~/workspace/aosp# hidl-gen -o $LOC -Lc++-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport $PACKAGE
ERROR: Failed to lookup type 'ITestCallback' at /mnt/f/ubuntu_win/aosp/hardware/interfaces/test/1.0/ITest.hal:9.31-38
ERROR: Could not parse android.hardware.test@1.0::ITest. Aborting.

 
 
 
 
  • 1
  • 2
  • 3

3.语法错误,boolean改成bool

root@BDJS-PF1LR28T:~/workspace/aosp# hidl-gen -o $LOC -Lc++-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport $PACKAGE
ERROR: boolean is a Java keyword and is therefore not a valid identifier at /mnt/f/ubuntu_win/aosp/hardware/interfaces/test/1.0/ITest.hal:9.52-58
ERROR: Could not parse android.hardware.test@1.0::ITest. Aborting.

 
 
 
 
  • 1
  • 2
  • 3

4.玄学bug 怀疑是没有make clean 导致的 也可电脑配置太低 如果之前能全编通过 你也没有修改报错的目录,再次编译就好,然后可能就会发现这个错误没有了,会有新的错误,再次编译直到报错到你的目录或者编译通过,要每次都检查下TARGET_PRODUCT=aosp_car_x86_64 是不是之前你lunch的那个,有时候这个也会变。

PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=9
TARGET_PRODUCT=aosp_car_x86_64
TARGET_BUILD_VARIANT=eng
TARGET_BUILD_TYPE=release
TARGET_ARCH=x86_64
TARGET_ARCH_VARIANT=x86_64
TARGET_2ND_ARCH=x86
TARGET_2ND_ARCH_VARIANT=x86_64
HOST_ARCH=x86_64
HOST_2ND_ARCH=x86
HOST_OS=linux
HOST_OS_EXTRA=Linux-4.4.0-17134-Microsoft-x86_64-Ubuntu-16.04.5-LTS
HOST_CROSS_OS=windows
HOST_CROSS_ARCH=x86
HOST_CROSS_2ND_ARCH=x86_64
HOST_BUILD_TYPE=release
BUILD_ID=PPR1.180610.011
OUT_DIR=out

[1/1] out/soong/.bootstrap/bin/soong_build out/soong/build.ninja
FAILED: out/soong/build.ninja
out/soong/.bootstrap/bin/soong_build -t -l out/.module_paths/Android.bp.list -b out/soong -n out -d out/soong/build.ninja.d -o out/soong/build.ninja Android.bp
error: external/llvm/tools/llvm-readobj/Android.bp:5:1: module “llvm-readobj” variant “linux_glibc_x86_64”: module source path external/llvm/tools/llvm-readobj does not exist
ninja: build stopped: subcommand failed.
16:13:52 soong bootstrap failed with: exit status 1

ninja: no work to do.
[1/1] out/soong/.bootstrap/bin/soong_build out/soong/build.ninja
FAILED: out/soong/build.ninja
out/soong/.bootstrap/bin/soong_build -t -l out/.module_paths/Android.bp.list -b out/soong -n out -d out/soong/build.ninja.d -o out/soong/build.ninja Android.bp
error: external/llvm/tools/llvm-readobj/Android.bp:5:1: module “llvm-readobj” variant “linux_glibc_x86_64”: module source path external/llvm/tools/llvm-readobj does not exist
ninja: build stopped: subcommand failed.
16:13:52 soong bootstrap failed with: exit status 1

ninja: no work to do.
[1/1] out/soong/.bootstrap/bin/soong_build out/soong/build.ninja
FAILED: out/soong/build.ninja
out/soong/.bootstrap/bin/soong_build -t -l out/.module_paths/Android.bp.list -b out/soong -n out -d out/soong/build.ninja.d -o out/soong/build.ninja Android.bp
error: external/ltp/gen.bp:10404:1: module “ltp_getpriority02” variant “android_x86_x86_64_core”: module source path external/ltp/testcases/kernel/syscalls/getpriority/getpriority02.c does not exist
error: external/ltp/gen.bp:1517:1: module “ltp_uname02” variant “android_x86_x86_64_core”: module source path external/ltp does not exist
error: external/ltp/gen.bp:1517:1: module “ltp_uname02” variant “android_x86_x86_64_core”: module source path external/ltp/testcases/kernel/syscalls/uname/uname02.c does not exist
ninja: build stopped: subcommand failed.
16:16:32 soong bootstrap failed with: exit status 1

16:23:33 Could not create module-finder: finder encountered 1 errors: [/mnt/f/ubuntu_win/aosp/external/clang/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/include-fixed/nan2008/el: lstat /mnt/f/ubuntu_win/aosp/external/clang/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/include-fixed/nan2008/el: no such file or directory]

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

5.vndk相关

出现下面错误,删除aosp\out\target\product\generic_x86_64\obj\PACKAGING\vndk_intermediates里的libs.txt,保证aosp\build\make\target\product\vndk 里的28.txt current.txt相同 注意要保持字母顺序添加

FAILED: out/target/product/generic_x86_64/obj/PACKAGING/vndk_intermediates/check-list-timestamp
/bin/bash -c "(( diff --old-line-format=\"Removed %L\"    --new-line-format=\"Added %L\"     --unchanged-line-format=\"\"    build/make/target/product/vndk/28.txt out/target/product/generic_x86_64/obj/PACKAGING/vndk_intermediates/libs.txt          || ( echo -e \" error: VNDK library list has been changed.\\n\" \"       Changing the VNDK library list is not allowed in API locked branches.\"; exit 1 )) ) && (mkdir -p out/target/product/generic_x86_64/obj/PACKAGING/vndk_intermediates/ ) && (touch out/target/product/generic_x86_64/obj/PACKAGING/vndk_intermediates/check-list-timestamp )"
Added VNDK-core: android.hardware.test@1.0.so
 error: VNDK library list has been changed.
        Changing the VNDK library list is not allowed in API locked branches.

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5

6.API相关 更新下api make update-api

[ 21% 321/1522] Checking API:  checkpublicapi-current
FAILED: out/target/common/obj/PACKAGING/checkpublicapi-current-timestamp
/bin/bash -c "(( out/host/linux-x86/bin/apicheck -JXmx1024m -J\"classpath out/host/linux-x86/framework/doclava.jar:out/host/linux-x86/framework/jsilver.jar:prebuilts/jdk/jdk8/linux-x86/lib/tools.jar:)\"  -error 2 -error 3 -error 4 -error 5 -error 6 -error 7 -error 8 -error 9 -error 10 -error 11 -error 12 -error 13 -error 14 -error 15 -error 16 -error 17 -error 18 -error 19 -error 20 -error 21 -error 23 -error 24 -error 25 -error 26 -error 27  frameworks/base/api/current.txt  out/target/common/obj/PACKAGING/public_api.txt  frameworks/base/api/removed.txt  out/target/common/obj/PACKAGING/removed.txt || (  cat build/make/core/apicheck_msg_current.txt ; exit 38 ) ) ) && (mkdir -p out/target/common/obj/PACKAGING/ ) && (touch out/target/common/obj/PACKAGING/checkpublicapi-current-timestamp )"
out/target/common/obj/PACKAGING/public_api.txt:9538: error 5: Added public field android.content.Context.TEST_SERVICE
out/target/common/obj/PACKAGING/public_api.txt:33637: error 2: Added package android.os.test

You have tried to change the API from what has been previously approved.

To make these errors go away, you have two choices:

  1. You can add “@hide” javadoc comments to the methods, etc. listed in the
    errors above.

  2. You can update current.txt by executing the following command:
    make update-api

    To submit the revised current.txt to the main Android repository,
    you will need approval.


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

7 AIDL 编译错误 Android.bp 里不需要添加aidl的自定义变量类 如 parcelable TestListenerEvent;

Exception in thread "main" java.nio.file.NoSuchFileException: out/soong/.intermediates/frameworks/base/framework/android_common/gen/aidl/frameworks/base/core/java/android/os/test/TestListenerEvent.java
        at java.base/sun.nio.fs.UnixException.translateToIOException(UnixException.java:92)
        at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:111)
        at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:116)
        at java.base/sun.nio.fs.UnixFileSystemProvider.newByteChannel(UnixFileSystemProvider.java:215)
        at java.base/java.nio.file.Files.newByteChannel(Files.java:369)
        at java.base/java.nio.file.Files.newByteChannel(Files.java:415)
        at java.base/java.nio.file.Files.readAllBytes(Files.java:3207)
        at com.google.turbine.main.Main.parseAll(Main.java:105)
        at com.google.turbine.main.Main.compile(Main.java:69)
        at com.google.turbine.main.Main.compile(Main.java:61)
        at com.google.turbine.main.Main.main(Main.java:56)

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

8 资源文件找不到错误 如果检查后不是自己的新添加的图片,直接再次全编。如果是自己的文件检查下是不是用了V7 V4的外部引用包资源主题背景等。

checkdir error:  cannot create out/target/common/obj/JAVA_LIBRARIES/android_system_stubs_current_intermediates/classes/res
                 No such file or directory
                 unable to process res/drawable-xhdpi-v4/btn_check_on_holo_dark.png.
checkdir error:  cannot create out/target/common/obj/JAVA_LIBRARIES/android_system_stubs_current_intermediates/classes/res
                 No such file or directory
                 unable to process res/drawable-xhdpi-v4/btn_check_on_holo_light.png.
checkdir error:  cannot create out/target/common/obj/JAVA_LIBRARIES/android_system_stubs_current_intermediates/classes/res
                 No such file or directory
                 unable to process res/drawable-xhdpi-v4/btn_check_on_pressed.png.
checkdir error:  cannot create out/target/common/obj/JAVA_LIBRARIES/android_system_stubs_current_intermediates/classes/res
                 No such file or directory
                 unable to process res/drawable-xhdpi-v4/btn_check_on_pressed_holo_dark.png.
checkdir error:  cannot create out/target/common/obj/JAVA_LIBRARIES/android_system_stubs_current_intermediates/classes/res
                 No such file or directory
                 unable to process res/drawable-xhdpi-v4/btn_check_on_pressed_holo_light.png.

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
                                </div>
            <link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-e9f16cbbc2.css" rel="stylesheet">
                </div>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值