upload android base code part4
This commit is contained in:
parent
b9e30e05b1
commit
78ea2404cd
23455 changed files with 5250148 additions and 0 deletions
38
android/hardware/google/apf/Android.mk
Normal file
38
android/hardware/google/apf/Android.mk
Normal file
|
@ -0,0 +1,38 @@
|
|||
# Copyright 2016 The Android Open Source Project
|
||||
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
|
||||
APF_CFLAGS := -DAPF_FRAME_HEADER_SIZE=14 \
|
||||
-Wall \
|
||||
-Werror
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_INCLUDES += $(LOCAL_PATH)
|
||||
|
||||
LOCAL_CFLAGS += $(APF_CFLAGS)
|
||||
|
||||
LOCAL_SRC_FILES += apf_interpreter.c
|
||||
|
||||
LOCAL_MODULE:= libapf
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_CFLAGS += $(APF_CFLAGS)
|
||||
LOCAL_SRC_FILES += apf_disassembler.c
|
||||
LOCAL_MODULE := apf_disassembler
|
||||
LOCAL_MODULE_TAGS := debug
|
||||
|
||||
include $(BUILD_HOST_EXECUTABLE)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_CFLAGS += $(APF_CFLAGS)
|
||||
LOCAL_SRC_FILES += apf_run.c apf_interpreter.c
|
||||
LOCAL_MODULE := apf_run
|
||||
LOCAL_MODULE_TAGS := debug
|
||||
|
||||
include $(BUILD_HOST_EXECUTABLE)
|
201
android/hardware/google/apf/LICENSE
Normal file
201
android/hardware/google/apf/LICENSE
Normal file
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
0
android/hardware/google/apf/MODULE_LICENSE_APACHE2
Normal file
0
android/hardware/google/apf/MODULE_LICENSE_APACHE2
Normal file
6
android/hardware/google/apf/OWNERS
Normal file
6
android/hardware/google/apf/OWNERS
Normal file
|
@ -0,0 +1,6 @@
|
|||
per-file Android.bp = build.master@android.com
|
||||
|
||||
ek@google.com
|
||||
hugobenichi@google.com
|
||||
lorenzo@google.com
|
||||
pauljensen@google.com
|
161
android/hardware/google/apf/apf.h
Normal file
161
android/hardware/google/apf/apf.h
Normal file
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* Copyright 2016, The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// A brief overview of APF:
|
||||
//
|
||||
// APF machine is composed of:
|
||||
// 1. A read-only program consisting of bytecodes as described below.
|
||||
// 2. Two 32-bit registers, called R0 and R1.
|
||||
// 3. Sixteen 32-bit memory slots.
|
||||
// 4. A read-only packet.
|
||||
// The program is executed by the interpreter below and parses the packet
|
||||
// to determine if the application processor (AP) should be woken up to
|
||||
// handle the packet or if can be dropped.
|
||||
//
|
||||
// APF bytecode description:
|
||||
//
|
||||
// The APF interpreter uses big-endian byte order for loads from the packet
|
||||
// and for storing immediates in instructions.
|
||||
//
|
||||
// Each instruction starts with a byte composed of:
|
||||
// Top 5 bits form "opcode" field, see *_OPCODE defines below.
|
||||
// Next 2 bits form "size field", which indicate the length of an immediate
|
||||
// value which follows the first byte. Values in this field:
|
||||
// 0 => immediate value is 0 and no bytes follow.
|
||||
// 1 => immediate value is 1 byte big.
|
||||
// 2 => immediate value is 2 bytes big.
|
||||
// 3 => immediate value is 4 bytes big.
|
||||
// Bottom bit forms "register" field, which indicates which register this
|
||||
// instruction operates on.
|
||||
//
|
||||
// There are three main categories of instructions:
|
||||
// Load instructions
|
||||
// These instructions load byte(s) of the packet into a register.
|
||||
// They load either 1, 2 or 4 bytes, as determined by the "opcode" field.
|
||||
// They load into the register specified by the "register" field.
|
||||
// The immediate value that follows the first byte of the instruction is
|
||||
// the byte offset from the begining of the packet to load from.
|
||||
// There are "indexing" loads which add the value in R1 to the byte offset
|
||||
// to load from. The "opcode" field determines which loads are "indexing".
|
||||
// Arithmetic instructions
|
||||
// These instructions perform simple operations, like addition, on register
|
||||
// values. The result of these instructions is always written into R0. One
|
||||
// argument of the arithmetic operation is R0's value. The other argument
|
||||
// of the arithmetic operation is determined by the "register" field:
|
||||
// If the "register" field is 0 then the immediate value following
|
||||
// the first byte of the instruction is used as the other argument
|
||||
// to the arithmetic operation.
|
||||
// If the "register" field is 1 then R1's value is used as the other
|
||||
// argument to the arithmetic operation.
|
||||
// Conditional jump instructions
|
||||
// These instructions compare register R0's value with another value, and if
|
||||
// the comparison succeeds, jump (i.e. adjust the program counter). The
|
||||
// immediate value that follows the first byte of the instruction
|
||||
// represents the jump target offset, i.e. the value added to the program
|
||||
// counter if the comparison succeeds. The other value compared is
|
||||
// determined by the "register" field:
|
||||
// If the "register" field is 0 then another immediate value
|
||||
// follows the jump target offset. This immediate value is of the
|
||||
// same size as the jump target offset, and represents the value
|
||||
// to compare against.
|
||||
// If the "register" field is 1 then register R1's value is
|
||||
// compared against.
|
||||
// The type of comparison (e.g. equal to, greater than etc) is determined
|
||||
// by the "opcode" field. The comparison interprets both values being
|
||||
// compared as unsigned values.
|
||||
//
|
||||
// Miscellaneous details:
|
||||
//
|
||||
// Pre-filled memory slot values
|
||||
// When the APF program begins execution, three of the sixteen memory slots
|
||||
// are pre-filled by the interpreter with values that may be useful for
|
||||
// programs:
|
||||
// Slot #13 is filled with the IPv4 header length. This value is calculated
|
||||
// by loading the first byte of the IPv4 header and taking the
|
||||
// bottom 4 bits and multiplying their value by 4. This value is
|
||||
// set to zero if the first 4 bits after the link layer header are
|
||||
// not 4, indicating not IPv4.
|
||||
// Slot #14 is filled with size of the packet in bytes, including the
|
||||
// link-layer header if any.
|
||||
// Slot #15 is filled with the filter age in seconds. This is the number of
|
||||
// seconds since the AP send the program to the chipset. This may
|
||||
// be used by filters that should have a particular lifetime. For
|
||||
// example, it can be used to rate-limit particular packets to one
|
||||
// every N seconds.
|
||||
// Special jump targets:
|
||||
// When an APF program executes a jump to the byte immediately after the last
|
||||
// byte of the progam (i.e., one byte past the end of the program), this
|
||||
// signals the program has completed and determined the packet should be
|
||||
// passed to the AP.
|
||||
// When an APF program executes a jump two bytes past the end of the program,
|
||||
// this signals the program has completed and determined the packet should
|
||||
// be dropped.
|
||||
// Jump if byte sequence doesn't match:
|
||||
// This is a special instruction to facilitate matching long sequences of
|
||||
// bytes in the packet. Initially it is encoded like a conditional jump
|
||||
// instruction with two exceptions:
|
||||
// The first byte of the instruction is always followed by two immediate
|
||||
// fields: The first immediate field is the jump target offset like other
|
||||
// conditional jump instructions. The second immediate field specifies the
|
||||
// number of bytes to compare.
|
||||
// These two immediate fields are followed by a sequence of bytes. These
|
||||
// bytes are compared with the bytes in the packet starting from the
|
||||
// position specified by the value of the register specified by the
|
||||
// "register" field of the instruction.
|
||||
|
||||
// Number of memory slots, see ldm/stm instructions.
|
||||
#define MEMORY_ITEMS 16
|
||||
// Upon program execution starting some memory slots are prefilled:
|
||||
#define MEMORY_OFFSET_IPV4_HEADER_SIZE 13 // 4*([APF_FRAME_HEADER_SIZE]&15)
|
||||
#define MEMORY_OFFSET_PACKET_SIZE 14 // Size of packet in bytes.
|
||||
#define MEMORY_OFFSET_FILTER_AGE 15 // Age since filter installed in seconds.
|
||||
|
||||
// Leave 0 opcode unused as it's a good indicator of accidental incorrect execution (e.g. data).
|
||||
#define LDB_OPCODE 1 // Load 1 byte from immediate offset, e.g. "ldb R0, [5]"
|
||||
#define LDH_OPCODE 2 // Load 2 bytes from immediate offset, e.g. "ldh R0, [5]"
|
||||
#define LDW_OPCODE 3 // Load 4 bytes from immediate offset, e.g. "ldw R0, [5]"
|
||||
#define LDBX_OPCODE 4 // Load 1 byte from immediate offset plus register, e.g. "ldbx R0, [5]R0"
|
||||
#define LDHX_OPCODE 5 // Load 2 byte from immediate offset plus register, e.g. "ldhx R0, [5]R0"
|
||||
#define LDWX_OPCODE 6 // Load 4 byte from immediate offset plus register, e.g. "ldwx R0, [5]R0"
|
||||
#define ADD_OPCODE 7 // Add, e.g. "add R0,5"
|
||||
#define MUL_OPCODE 8 // Multiply, e.g. "mul R0,5"
|
||||
#define DIV_OPCODE 9 // Divide, e.g. "div R0,5"
|
||||
#define AND_OPCODE 10 // And, e.g. "and R0,5"
|
||||
#define OR_OPCODE 11 // Or, e.g. "or R0,5"
|
||||
#define SH_OPCODE 12 // Left shift, e.g, "sh R0, 5" or "sh R0, -5" (shifts right)
|
||||
#define LI_OPCODE 13 // Load immediate, e.g. "li R0,5" (immediate encoded as signed value)
|
||||
#define JMP_OPCODE 14 // Unconditional jump, e.g. "jmp label"
|
||||
#define JEQ_OPCODE 15 // Compare equal and branch, e.g. "jeq R0,5,label"
|
||||
#define JNE_OPCODE 16 // Compare not equal and branch, e.g. "jne R0,5,label"
|
||||
#define JGT_OPCODE 17 // Compare greater than and branch, e.g. "jgt R0,5,label"
|
||||
#define JLT_OPCODE 18 // Compare less than and branch, e.g. "jlt R0,5,label"
|
||||
#define JSET_OPCODE 19 // Compare any bits set and branch, e.g. "jset R0,5,label"
|
||||
#define JNEBS_OPCODE 20 // Compare not equal byte sequence, e.g. "jnebs R0,5,label,0x1122334455"
|
||||
#define EXT_OPCODE 21 // Immediate value is one of *_EXT_OPCODE
|
||||
// Extended opcodes. These all have an opcode of EXT_OPCODE
|
||||
// and specify the actual opcode in the immediate field.
|
||||
#define LDM_EXT_OPCODE 0 // Load from memory, e.g. "ldm R0,5"
|
||||
// Values 0-15 represent loading the different memory slots.
|
||||
#define STM_EXT_OPCODE 16 // Store to memory, e.g. "stm R0,5"
|
||||
// Values 16-31 represent storing to the different memory slots.
|
||||
#define NOT_EXT_OPCODE 32 // Not, e.g. "not R0"
|
||||
#define NEG_EXT_OPCODE 33 // Negate, e.g. "neg R0"
|
||||
#define SWAP_EXT_OPCODE 34 // Swap, e.g. "swap R0,R1"
|
||||
#define MOV_EXT_OPCODE 35 // Move, e.g. "move R0,R1"
|
||||
|
||||
#define EXTRACT_OPCODE(i) (((i) >> 3) & 31)
|
||||
#define EXTRACT_REGISTER(i) ((i) & 1)
|
||||
#define EXTRACT_IMM_LENGTH(i) (((i) >> 1) & 3)
|
217
android/hardware/google/apf/apf_disassembler.c
Normal file
217
android/hardware/google/apf/apf_disassembler.c
Normal file
|
@ -0,0 +1,217 @@
|
|||
/*
|
||||
* Copyright 2016, The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "apf.h"
|
||||
|
||||
// If "c" is of an unsigned type, generate a compile warning that gets promoted to an error.
|
||||
// This makes bounds checking simpler because ">= 0" can be avoided. Otherwise adding
|
||||
// superfluous ">= 0" with unsigned expressions generates compile warnings.
|
||||
#define ENFORCE_UNSIGNED(c) ((c)==(uint32_t)(c))
|
||||
|
||||
static void print_opcode(const char* opcode) {
|
||||
printf("%-6s", opcode);
|
||||
}
|
||||
|
||||
// Mapping from opcode number to opcode name.
|
||||
static const char* opcode_names [] = {
|
||||
[LDB_OPCODE] = "ldb",
|
||||
[LDH_OPCODE] = "ldh",
|
||||
[LDW_OPCODE] = "ldw",
|
||||
[LDBX_OPCODE] = "ldb",
|
||||
[LDHX_OPCODE] = "ldh",
|
||||
[LDWX_OPCODE] = "ldw",
|
||||
[ADD_OPCODE] = "add",
|
||||
[MUL_OPCODE] = "mul",
|
||||
[DIV_OPCODE] = "div",
|
||||
[AND_OPCODE] = "and",
|
||||
[OR_OPCODE] = "or",
|
||||
[SH_OPCODE] = "sh",
|
||||
[LI_OPCODE] = "li",
|
||||
[JMP_OPCODE] = "jmp",
|
||||
[JEQ_OPCODE] = "jeq",
|
||||
[JNE_OPCODE] = "jne",
|
||||
[JGT_OPCODE] = "jgt",
|
||||
[JLT_OPCODE] = "jlt",
|
||||
[JSET_OPCODE] = "jset",
|
||||
[JNEBS_OPCODE] = "jnebs",
|
||||
};
|
||||
|
||||
static void print_jump_target(uint32_t target, uint32_t program_len) {
|
||||
if (target == program_len) {
|
||||
printf("pass");
|
||||
} else if (target == program_len + 1) {
|
||||
printf("drop");
|
||||
} else {
|
||||
printf("%u", target);
|
||||
}
|
||||
}
|
||||
|
||||
// Disassembles an APF program. A hex dump of the program is supplied on stdin.
|
||||
//
|
||||
// NOTE: This is a simple debugging tool not meant for shipping or production use. It is by no
|
||||
// means hardened against malicious input and contains known vulnerabilities.
|
||||
//
|
||||
// Example usage:
|
||||
// adb shell dumpsys wifi ipmanager | sed '/Last program:/,+1!d;/Last program:/d;s/[ ]*//' | out/host/linux-x86/bin/apf_disassembler
|
||||
int main(void) {
|
||||
uint32_t program_len = 0;
|
||||
uint8_t program[10000];
|
||||
|
||||
// Read in hex program bytes
|
||||
int byte;
|
||||
while (scanf("%2x", &byte) == 1 && program_len < sizeof(program)) {
|
||||
program[program_len++] = byte;
|
||||
}
|
||||
|
||||
for (uint32_t pc = 0; pc < program_len;) {
|
||||
printf("%8u: ", pc);
|
||||
const uint8_t bytecode = program[pc++];
|
||||
const uint32_t opcode = EXTRACT_OPCODE(bytecode);
|
||||
#define PRINT_OPCODE() print_opcode(opcode_names[opcode])
|
||||
const uint32_t reg_num = EXTRACT_REGISTER(bytecode);
|
||||
// All instructions have immediate fields, so load them now.
|
||||
const uint32_t len_field = EXTRACT_IMM_LENGTH(bytecode);
|
||||
uint32_t imm = 0;
|
||||
int32_t signed_imm = 0;
|
||||
if (len_field != 0) {
|
||||
const uint32_t imm_len = 1 << (len_field - 1);
|
||||
uint32_t i;
|
||||
for (i = 0; i < imm_len && pc < program_len; i++)
|
||||
imm = (imm << 8) | program[pc++];
|
||||
// Sign extend imm into signed_imm.
|
||||
signed_imm = imm << ((4 - imm_len) * 8);
|
||||
signed_imm >>= (4 - imm_len) * 8;
|
||||
}
|
||||
switch (opcode) {
|
||||
case LDB_OPCODE:
|
||||
case LDH_OPCODE:
|
||||
case LDW_OPCODE:
|
||||
PRINT_OPCODE();
|
||||
printf("r%d, [%u]", reg_num, imm);
|
||||
break;
|
||||
case LDBX_OPCODE:
|
||||
case LDHX_OPCODE:
|
||||
case LDWX_OPCODE:
|
||||
PRINT_OPCODE();
|
||||
printf("r%d, [%u+r1]", reg_num, imm);
|
||||
break;
|
||||
case JMP_OPCODE:
|
||||
PRINT_OPCODE();
|
||||
print_jump_target(pc + imm, program_len);
|
||||
break;
|
||||
case JEQ_OPCODE:
|
||||
case JNE_OPCODE:
|
||||
case JGT_OPCODE:
|
||||
case JLT_OPCODE:
|
||||
case JSET_OPCODE:
|
||||
case JNEBS_OPCODE: {
|
||||
PRINT_OPCODE();
|
||||
printf("r0, ");
|
||||
// Load second immediate field.
|
||||
uint32_t cmp_imm = 0;
|
||||
if (reg_num == 1) {
|
||||
printf("r1, ");
|
||||
} else if (len_field == 0) {
|
||||
printf("0, ");
|
||||
} else {
|
||||
uint32_t cmp_imm_len = 1 << (len_field - 1);
|
||||
uint32_t i;
|
||||
for (i = 0; i < cmp_imm_len && pc < program_len; i++)
|
||||
cmp_imm = (cmp_imm << 8) | program[pc++];
|
||||
printf("0x%x, ", cmp_imm);
|
||||
}
|
||||
if (opcode == JNEBS_OPCODE) {
|
||||
print_jump_target(pc + imm + cmp_imm, program_len);
|
||||
printf(", ");
|
||||
while (cmp_imm--)
|
||||
printf("%02x", program[pc++]);
|
||||
} else {
|
||||
print_jump_target(pc + imm, program_len);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ADD_OPCODE:
|
||||
case SH_OPCODE:
|
||||
PRINT_OPCODE();
|
||||
if (reg_num) {
|
||||
printf("r0, r1");
|
||||
} else {
|
||||
printf("r0, %d", signed_imm);
|
||||
}
|
||||
break;
|
||||
case MUL_OPCODE:
|
||||
case DIV_OPCODE:
|
||||
case AND_OPCODE:
|
||||
case OR_OPCODE:
|
||||
PRINT_OPCODE();
|
||||
if (reg_num) {
|
||||
printf("r0, r1");
|
||||
} else {
|
||||
printf("r0, %u", imm);
|
||||
}
|
||||
break;
|
||||
case LI_OPCODE:
|
||||
PRINT_OPCODE();
|
||||
printf("r%d, %d", reg_num, signed_imm);
|
||||
break;
|
||||
case EXT_OPCODE:
|
||||
if (
|
||||
// If LDM_EXT_OPCODE is 0 and imm is compared with it, a compiler error will result,
|
||||
// instead just enforce that imm is unsigned (so it's always greater or equal to 0).
|
||||
#if LDM_EXT_OPCODE == 0
|
||||
ENFORCE_UNSIGNED(imm) &&
|
||||
#else
|
||||
imm >= LDM_EXT_OPCODE &&
|
||||
#endif
|
||||
imm < (LDM_EXT_OPCODE + MEMORY_ITEMS)) {
|
||||
print_opcode("ldm");
|
||||
printf("r%d, m[%u]", reg_num, imm - LDM_EXT_OPCODE);
|
||||
} else if (imm >= STM_EXT_OPCODE && imm < (STM_EXT_OPCODE + MEMORY_ITEMS)) {
|
||||
print_opcode("stm");
|
||||
printf("r%d, m[%u]", reg_num, imm - STM_EXT_OPCODE);
|
||||
} else switch (imm) {
|
||||
case NOT_EXT_OPCODE:
|
||||
print_opcode("not");
|
||||
printf("r%d", reg_num);
|
||||
break;
|
||||
case NEG_EXT_OPCODE:
|
||||
print_opcode("neg");
|
||||
printf("r%d", reg_num);
|
||||
break;
|
||||
case SWAP_EXT_OPCODE:
|
||||
print_opcode("swap");
|
||||
break;
|
||||
case MOV_EXT_OPCODE:
|
||||
print_opcode("mov");
|
||||
printf("r%d, r%d", reg_num, reg_num ^ 1);
|
||||
break;
|
||||
default:
|
||||
printf("unknown_ext %u", imm);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
// Unknown opcode
|
||||
default:
|
||||
printf("unknown %u", opcode);
|
||||
break;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
278
android/hardware/google/apf/apf_interpreter.c
Normal file
278
android/hardware/google/apf/apf_interpreter.c
Normal file
|
@ -0,0 +1,278 @@
|
|||
/*
|
||||
* Copyright 2016, The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "apf_interpreter.h"
|
||||
|
||||
#include <string.h> // For memcmp
|
||||
|
||||
#include "apf.h"
|
||||
|
||||
// Return code indicating "packet" should accepted.
|
||||
#define PASS_PACKET 1
|
||||
// Return code indicating "packet" should be dropped.
|
||||
#define DROP_PACKET 0
|
||||
// Verify an internal condition and accept packet if it fails.
|
||||
#define ASSERT_RETURN(c) if (!(c)) return PASS_PACKET
|
||||
// If "c" is of an unsigned type, generate a compile warning that gets promoted to an error.
|
||||
// This makes bounds checking simpler because ">= 0" can be avoided. Otherwise adding
|
||||
// superfluous ">= 0" with unsigned expressions generates compile warnings.
|
||||
#define ENFORCE_UNSIGNED(c) ((c)==(uint32_t)(c))
|
||||
|
||||
/**
|
||||
* Runs a packet filtering program over a packet.
|
||||
*
|
||||
* @param program the program bytecode.
|
||||
* @param program_len the length of {@code apf_program} in bytes.
|
||||
* @param packet the packet bytes, starting from the 802.3 header and not
|
||||
* including any CRC bytes at the end.
|
||||
* @param packet_len the length of {@code packet} in bytes.
|
||||
* @param filter_age the number of seconds since the filter was programmed.
|
||||
*
|
||||
* @return non-zero if packet should be passed to AP, zero if
|
||||
* packet should be dropped.
|
||||
*/
|
||||
int accept_packet(const uint8_t* program, uint32_t program_len,
|
||||
const uint8_t* packet, uint32_t packet_len,
|
||||
uint32_t filter_age) {
|
||||
// Is offset within program bounds?
|
||||
#define IN_PROGRAM_BOUNDS(p) (ENFORCE_UNSIGNED(p) && (p) < program_len)
|
||||
// Is offset within packet bounds?
|
||||
#define IN_PACKET_BOUNDS(p) (ENFORCE_UNSIGNED(p) && (p) < packet_len)
|
||||
// Accept packet if not within program bounds
|
||||
#define ASSERT_IN_PROGRAM_BOUNDS(p) ASSERT_RETURN(IN_PROGRAM_BOUNDS(p))
|
||||
// Accept packet if not within packet bounds
|
||||
#define ASSERT_IN_PACKET_BOUNDS(p) ASSERT_RETURN(IN_PACKET_BOUNDS(p))
|
||||
// Program counter.
|
||||
uint32_t pc = 0;
|
||||
// Accept packet if not within program or not ahead of program counter
|
||||
#define ASSERT_FORWARD_IN_PROGRAM(p) ASSERT_RETURN(IN_PROGRAM_BOUNDS(p) && (p) >= pc)
|
||||
// Memory slot values.
|
||||
uint32_t memory[MEMORY_ITEMS] = {};
|
||||
// Fill in pre-filled memory slot values.
|
||||
memory[MEMORY_OFFSET_PACKET_SIZE] = packet_len;
|
||||
memory[MEMORY_OFFSET_FILTER_AGE] = filter_age;
|
||||
ASSERT_IN_PACKET_BOUNDS(APF_FRAME_HEADER_SIZE);
|
||||
// Only populate if IP version is IPv4.
|
||||
if ((packet[APF_FRAME_HEADER_SIZE] & 0xf0) == 0x40) {
|
||||
memory[MEMORY_OFFSET_IPV4_HEADER_SIZE] = (packet[APF_FRAME_HEADER_SIZE] & 15) * 4;
|
||||
}
|
||||
// Register values.
|
||||
uint32_t registers[2] = {};
|
||||
// Count of instructions remaining to execute. This is done to ensure an
|
||||
// upper bound on execution time. It should never be hit and is only for
|
||||
// safety. Initialize to the number of bytes in the program which is an
|
||||
// upper bound on the number of instructions in the program.
|
||||
uint32_t instructions_remaining = program_len;
|
||||
|
||||
do {
|
||||
if (pc == program_len) {
|
||||
return PASS_PACKET;
|
||||
} else if (pc == (program_len + 1)) {
|
||||
return DROP_PACKET;
|
||||
}
|
||||
ASSERT_IN_PROGRAM_BOUNDS(pc);
|
||||
const uint8_t bytecode = program[pc++];
|
||||
const uint32_t opcode = EXTRACT_OPCODE(bytecode);
|
||||
const uint32_t reg_num = EXTRACT_REGISTER(bytecode);
|
||||
#define REG (registers[reg_num])
|
||||
#define OTHER_REG (registers[reg_num ^ 1])
|
||||
// All instructions have immediate fields, so load them now.
|
||||
const uint32_t len_field = EXTRACT_IMM_LENGTH(bytecode);
|
||||
uint32_t imm = 0;
|
||||
int32_t signed_imm = 0;
|
||||
if (len_field != 0) {
|
||||
const uint32_t imm_len = 1 << (len_field - 1);
|
||||
ASSERT_FORWARD_IN_PROGRAM(pc + imm_len - 1);
|
||||
uint32_t i;
|
||||
for (i = 0; i < imm_len; i++)
|
||||
imm = (imm << 8) | program[pc++];
|
||||
// Sign extend imm into signed_imm.
|
||||
signed_imm = imm << ((4 - imm_len) * 8);
|
||||
signed_imm >>= (4 - imm_len) * 8;
|
||||
}
|
||||
switch (opcode) {
|
||||
case LDB_OPCODE:
|
||||
case LDH_OPCODE:
|
||||
case LDW_OPCODE:
|
||||
case LDBX_OPCODE:
|
||||
case LDHX_OPCODE:
|
||||
case LDWX_OPCODE: {
|
||||
uint32_t offs = imm;
|
||||
if (opcode >= LDBX_OPCODE) {
|
||||
// Note: this can overflow and actually decrease offs.
|
||||
offs += registers[1];
|
||||
}
|
||||
ASSERT_IN_PACKET_BOUNDS(offs);
|
||||
uint32_t load_size;
|
||||
switch (opcode) {
|
||||
case LDB_OPCODE:
|
||||
case LDBX_OPCODE:
|
||||
load_size = 1;
|
||||
break;
|
||||
case LDH_OPCODE:
|
||||
case LDHX_OPCODE:
|
||||
load_size = 2;
|
||||
break;
|
||||
case LDW_OPCODE:
|
||||
case LDWX_OPCODE:
|
||||
load_size = 4;
|
||||
break;
|
||||
// Immediately enclosing switch statement guarantees
|
||||
// opcode cannot be any other value.
|
||||
}
|
||||
const uint32_t end_offs = offs + (load_size - 1);
|
||||
// Catch overflow/wrap-around.
|
||||
ASSERT_RETURN(end_offs >= offs);
|
||||
ASSERT_IN_PACKET_BOUNDS(end_offs);
|
||||
uint32_t val = 0;
|
||||
while (load_size--)
|
||||
val = (val << 8) | packet[offs++];
|
||||
REG = val;
|
||||
break;
|
||||
}
|
||||
case JMP_OPCODE:
|
||||
// This can jump backwards. Infinite looping prevented by instructions_remaining.
|
||||
pc += imm;
|
||||
break;
|
||||
case JEQ_OPCODE:
|
||||
case JNE_OPCODE:
|
||||
case JGT_OPCODE:
|
||||
case JLT_OPCODE:
|
||||
case JSET_OPCODE:
|
||||
case JNEBS_OPCODE: {
|
||||
// Load second immediate field.
|
||||
uint32_t cmp_imm = 0;
|
||||
if (reg_num == 1) {
|
||||
cmp_imm = registers[1];
|
||||
} else if (len_field != 0) {
|
||||
uint32_t cmp_imm_len = 1 << (len_field - 1);
|
||||
ASSERT_FORWARD_IN_PROGRAM(pc + cmp_imm_len - 1);
|
||||
uint32_t i;
|
||||
for (i = 0; i < cmp_imm_len; i++)
|
||||
cmp_imm = (cmp_imm << 8) | program[pc++];
|
||||
}
|
||||
switch (opcode) {
|
||||
case JEQ_OPCODE:
|
||||
if (registers[0] == cmp_imm)
|
||||
pc += imm;
|
||||
break;
|
||||
case JNE_OPCODE:
|
||||
if (registers[0] != cmp_imm)
|
||||
pc += imm;
|
||||
break;
|
||||
case JGT_OPCODE:
|
||||
if (registers[0] > cmp_imm)
|
||||
pc += imm;
|
||||
break;
|
||||
case JLT_OPCODE:
|
||||
if (registers[0] < cmp_imm)
|
||||
pc += imm;
|
||||
break;
|
||||
case JSET_OPCODE:
|
||||
if (registers[0] & cmp_imm)
|
||||
pc += imm;
|
||||
break;
|
||||
case JNEBS_OPCODE: {
|
||||
// cmp_imm is size in bytes of data to compare.
|
||||
// pc is offset of program bytes to compare.
|
||||
// imm is jump target offset.
|
||||
// REG is offset of packet bytes to compare.
|
||||
ASSERT_FORWARD_IN_PROGRAM(pc + cmp_imm - 1);
|
||||
ASSERT_IN_PACKET_BOUNDS(REG);
|
||||
const uint32_t last_packet_offs = REG + cmp_imm - 1;
|
||||
ASSERT_RETURN(last_packet_offs >= REG);
|
||||
ASSERT_IN_PACKET_BOUNDS(last_packet_offs);
|
||||
if (memcmp(program + pc, packet + REG, cmp_imm))
|
||||
pc += imm;
|
||||
// skip past comparison bytes
|
||||
pc += cmp_imm;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ADD_OPCODE:
|
||||
registers[0] += reg_num ? registers[1] : imm;
|
||||
break;
|
||||
case MUL_OPCODE:
|
||||
registers[0] *= reg_num ? registers[1] : imm;
|
||||
break;
|
||||
case DIV_OPCODE: {
|
||||
const uint32_t div_operand = reg_num ? registers[1] : imm;
|
||||
ASSERT_RETURN(div_operand);
|
||||
registers[0] /= div_operand;
|
||||
break;
|
||||
}
|
||||
case AND_OPCODE:
|
||||
registers[0] &= reg_num ? registers[1] : imm;
|
||||
break;
|
||||
case OR_OPCODE:
|
||||
registers[0] |= reg_num ? registers[1] : imm;
|
||||
break;
|
||||
case SH_OPCODE: {
|
||||
const int32_t shift_val = reg_num ? (int32_t)registers[1] : signed_imm;
|
||||
if (shift_val > 0)
|
||||
registers[0] <<= shift_val;
|
||||
else
|
||||
registers[0] >>= -shift_val;
|
||||
break;
|
||||
}
|
||||
case LI_OPCODE:
|
||||
REG = signed_imm;
|
||||
break;
|
||||
case EXT_OPCODE:
|
||||
if (
|
||||
// If LDM_EXT_OPCODE is 0 and imm is compared with it, a compiler error will result,
|
||||
// instead just enforce that imm is unsigned (so it's always greater or equal to 0).
|
||||
#if LDM_EXT_OPCODE == 0
|
||||
ENFORCE_UNSIGNED(imm) &&
|
||||
#else
|
||||
imm >= LDM_EXT_OPCODE &&
|
||||
#endif
|
||||
imm < (LDM_EXT_OPCODE + MEMORY_ITEMS)) {
|
||||
REG = memory[imm - LDM_EXT_OPCODE];
|
||||
} else if (imm >= STM_EXT_OPCODE && imm < (STM_EXT_OPCODE + MEMORY_ITEMS)) {
|
||||
memory[imm - STM_EXT_OPCODE] = REG;
|
||||
} else switch (imm) {
|
||||
case NOT_EXT_OPCODE:
|
||||
REG = ~REG;
|
||||
break;
|
||||
case NEG_EXT_OPCODE:
|
||||
REG = -REG;
|
||||
break;
|
||||
case SWAP_EXT_OPCODE: {
|
||||
uint32_t tmp = REG;
|
||||
REG = OTHER_REG;
|
||||
OTHER_REG = tmp;
|
||||
break;
|
||||
}
|
||||
case MOV_EXT_OPCODE:
|
||||
REG = OTHER_REG;
|
||||
break;
|
||||
// Unknown extended opcode
|
||||
default:
|
||||
// Bail out
|
||||
return PASS_PACKET;
|
||||
}
|
||||
break;
|
||||
// Unknown opcode
|
||||
default:
|
||||
// Bail out
|
||||
return PASS_PACKET;
|
||||
}
|
||||
} while (instructions_remaining--);
|
||||
return PASS_PACKET;
|
||||
}
|
53
android/hardware/google/apf/apf_interpreter.h
Normal file
53
android/hardware/google/apf/apf_interpreter.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright 2015, The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef APF_INTERPRETER_H_
|
||||
#define APF_INTERPRETER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Version of APF instruction set processed by accept_packet().
|
||||
* Should be returned by wifi_get_packet_filter_info.
|
||||
*/
|
||||
#define APF_VERSION 2
|
||||
|
||||
/**
|
||||
* Runs a packet filtering program over a packet.
|
||||
*
|
||||
* @param program the program bytecode.
|
||||
* @param program_len the length of {@code apf_program} in bytes.
|
||||
* @param packet the packet bytes, starting from the 802.3 header and not
|
||||
* including any CRC bytes at the end.
|
||||
* @param packet_len the length of {@code packet} in bytes.
|
||||
* @param filter_age the number of seconds since the filter was programmed.
|
||||
*
|
||||
* @return non-zero if packet should be passed to AP, zero if
|
||||
* packet should be dropped.
|
||||
*/
|
||||
int accept_packet(const uint8_t* program, uint32_t program_len,
|
||||
const uint8_t* packet, uint32_t packet_len,
|
||||
uint32_t filter_age);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // APF_INTERPRETER_H_
|
74
android/hardware/google/apf/apf_run.c
Normal file
74
android/hardware/google/apf/apf_run.c
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright 2016, The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// Simple program to try running an APF program against a packet.
|
||||
|
||||
#include <libgen.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "apf_interpreter.h"
|
||||
|
||||
// Parses hex in "input". Allocates and fills "*output" with parsed bytes.
|
||||
// Returns length in bytes of "*output".
|
||||
int parse_hex(char* input, uint8_t** output) {
|
||||
int length = strlen(input);
|
||||
if (length & 1) {
|
||||
fprintf(stderr, "Argument not even number of characters: %s\n", input);
|
||||
exit(1);
|
||||
}
|
||||
length >>= 1;
|
||||
*output = malloc(length);
|
||||
if (*output == NULL) {
|
||||
fprintf(stderr, "Out of memory, tried to allocate %d\n", length);
|
||||
exit(1);
|
||||
}
|
||||
for (int i = 0; i < length; i++) {
|
||||
char byte[3] = { input[i*2], input[i*2+1], 0 };
|
||||
char* end_ptr;
|
||||
(*output)[i] = strtol(byte, &end_ptr, 16);
|
||||
if (end_ptr != byte + 2) {
|
||||
fprintf(stderr, "Failed to parse hex %s\n", byte);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != 4) {
|
||||
fprintf(stderr,
|
||||
"Usage: %s <program> <packet> <program age>\n"
|
||||
" program: APF program, in hex\n"
|
||||
" packet: Packet to run through program, in hex\n"
|
||||
" program age: Age of program in seconds.\n",
|
||||
basename(argv[0]));
|
||||
exit(1);
|
||||
}
|
||||
uint8_t* program;
|
||||
uint32_t program_len = parse_hex(argv[1], &program);
|
||||
uint8_t* packet;
|
||||
uint32_t packet_len = parse_hex(argv[2], &packet);
|
||||
uint32_t filter_age = atoi(argv[3]);
|
||||
int ret = accept_packet(program, program_len, packet, packet_len,
|
||||
filter_age);
|
||||
printf("Packet %sed\n", ret ? "pass" : "dropp");
|
||||
free(program);
|
||||
free(packet);
|
||||
return ret;
|
||||
}
|
16
android/hardware/google/easel/camera/Android.mk
Normal file
16
android/hardware/google/easel/camera/Android.mk
Normal file
|
@ -0,0 +1,16 @@
|
|||
# Copyright 2017 The Android Open Source Project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
ifeq ($(BOARD_USES_EASEL),true)
|
||||
include $(call all-subdir-makefiles)
|
||||
endif
|
126
android/hardware/google/easel/camera/include/HdrPlusProfiler.h
Normal file
126
android/hardware/google/easel/camera/include/HdrPlusProfiler.h
Normal file
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* Copyright 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef HDR_PLUS_PROFILER_H
|
||||
#define HDR_PLUS_PROFILER_H
|
||||
|
||||
#ifndef ENABLE_HDRPLUS_PROFILER
|
||||
#define ENABLE_HDRPLUS_PROFILER 0
|
||||
#endif
|
||||
|
||||
#if !ENABLE_HDRPLUS_PROFILER
|
||||
|
||||
// If profiler is not enabled, make every macro a noop
|
||||
#define DECLARE_PROFILER_TIMER(_var, _description)
|
||||
#define START_PROFILER_TIMER(_var) do {} while(0)
|
||||
#define END_PROFILER_TIMER(_var) do {} while(0)
|
||||
#define SCOPE_PROFILER_TIMER(_description) do {} while(0)
|
||||
|
||||
#else
|
||||
|
||||
#include <string>
|
||||
|
||||
/*
|
||||
* Declare a profiler timer.
|
||||
*
|
||||
* _var is the variable that will be declared as a timer.
|
||||
* _description is the description for this timer. It will be used when logging the timer duration.
|
||||
*/
|
||||
#define DECLARE_PROFILER_TIMER(_var, _description) pbcamera::TimerLogger _var = {_description}
|
||||
|
||||
/*
|
||||
* Start a timer.
|
||||
*
|
||||
* _var is a timer declared with DECALRE_PROFILER_TIMER.
|
||||
*/
|
||||
#define START_PROFILER_TIMER(_var) ((_var).start())
|
||||
|
||||
/*
|
||||
* End a timer and log the duration since last start.
|
||||
*
|
||||
* _var is a timer declared with DECALRE_PROFILER_TIMER.
|
||||
*/
|
||||
#define END_PROFILER_TIMER(_var) ((_var).end())
|
||||
|
||||
/*
|
||||
* Declare a scope timer that starts now and ends when it goes out of scope.
|
||||
*
|
||||
* __description is the description for this timer. It will be used when logging the timer duration.
|
||||
*/
|
||||
#define SCOPE_PROFILER_TIMER(_description) pbcamera::ScopeTimerLogger _timer(_description)
|
||||
|
||||
namespace pbcamera {
|
||||
|
||||
#define TIMER_TAG "[PROFILE_TIMER]"
|
||||
|
||||
/**
|
||||
* TimerLogger provides a timer to log the duration between start() and end().
|
||||
*/
|
||||
class TimerLogger {
|
||||
public:
|
||||
TimerLogger(const char *name) : mName(name), mInvalid(true) {};
|
||||
|
||||
// Start the timer.
|
||||
void start() {
|
||||
mInvalid = (clock_gettime(kClockId, &mStartTime) != 0);
|
||||
}
|
||||
|
||||
// End the timer and log the duration since last start.
|
||||
void end() {
|
||||
if (mInvalid) {
|
||||
ALOGE("%s <%s> start time is invalid.", TIMER_TAG, mName.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
struct timespec endTime;
|
||||
mInvalid = (clock_gettime(kClockId, &endTime) != 0);
|
||||
if (mInvalid) {
|
||||
ALOGE("%s <%s> end time is invalid.", TIMER_TAG, mName.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
int64_t startNs = static_cast<int64_t>(mStartTime.tv_sec) * kNsPerSec + mStartTime.tv_nsec;
|
||||
int64_t endNs = static_cast<int64_t>(endTime.tv_sec) * kNsPerSec + endTime.tv_nsec;
|
||||
ALOGI("%s <%s> took %f ms.", TIMER_TAG, mName.c_str(),
|
||||
static_cast<float>(endNs - startNs) / kNsPerMs);
|
||||
}
|
||||
|
||||
private:
|
||||
const static int64_t kNsPerSec = 1000000000;
|
||||
const static int64_t kNsPerMs = 1000000;
|
||||
const static clockid_t kClockId = CLOCK_BOOTTIME;
|
||||
|
||||
std::string mName;
|
||||
struct timespec mStartTime;
|
||||
bool mInvalid;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* ScopeTimerLogger provides a timer to log the duration of the instance lifetime.
|
||||
*/
|
||||
class ScopeTimerLogger {
|
||||
public:
|
||||
ScopeTimerLogger(const char *name) : mTimerLogger(name) { mTimerLogger.start(); };
|
||||
virtual ~ScopeTimerLogger() { mTimerLogger.end(); };
|
||||
private:
|
||||
TimerLogger mTimerLogger;
|
||||
};
|
||||
|
||||
} // namespace pbcamera
|
||||
|
||||
#endif // !ENABLE_HDRPLUS_PROFILER
|
||||
|
||||
#endif // HDR_PLUS_PROFILER_H
|
538
android/hardware/google/easel/camera/include/HdrPlusTypes.h
Normal file
538
android/hardware/google/easel/camera/include/HdrPlusTypes.h
Normal file
|
@ -0,0 +1,538 @@
|
|||
/*
|
||||
* Copyright 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef HDR_PLUS_TYPES_H
|
||||
#define HDR_PLUS_TYPES_H
|
||||
|
||||
#include <array>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace pbcamera {
|
||||
|
||||
// This file defines the common types used in HDR+ client and HDR+ service API.
|
||||
|
||||
typedef int32_t status_t;
|
||||
|
||||
/*
|
||||
* ImageConfiguration and PlaneConfiguration define the layout of a buffer.
|
||||
* The following is an example of a NV21 buffer.
|
||||
*
|
||||
* <-------Y stride (in bytes)------->
|
||||
* <----width (in pixels)---->
|
||||
* Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . ^ ^
|
||||
* Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . | |
|
||||
* Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . | |
|
||||
* Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . height Y scanline
|
||||
* Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . (in lines) (in lines)
|
||||
* Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . | |
|
||||
* Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . | |
|
||||
* Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . | |
|
||||
* Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . | |
|
||||
* Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . v |
|
||||
* . . . . . . . . . . . . . . . . . . |
|
||||
* . . . . . . . . . . . . . . . . . . v
|
||||
* <------V/U stride (in bytes)------>
|
||||
* V U V U V U V U V U V U V U . . . . ^
|
||||
* V U V U V U V U V U V U V U . . . . |
|
||||
* V U V U V U V U V U V U V U . . . . |
|
||||
* V U V U V U V U V U V U V U . . . . V/U scanline
|
||||
* V U V U V U V U V U V U V U . . . . (in lines)
|
||||
* . . . . . . . . . . . . . . . . . . |
|
||||
* . . . . . . . . . . . . . . . . . . v
|
||||
* . . . . . . . . . . . . . . . . . . -> Image padding.
|
||||
*/
|
||||
|
||||
// PlaneConfiguration defines an image planes configuration.
|
||||
struct PlaneConfiguration {
|
||||
// Number of bytes in each line including padding.
|
||||
uint32_t stride;
|
||||
// Number of lines vertically including padding.
|
||||
uint32_t scanline;
|
||||
|
||||
PlaneConfiguration() : stride(0), scanline(0) {};
|
||||
|
||||
bool operator==(const PlaneConfiguration &other) const {
|
||||
return stride == other.stride &&
|
||||
scanline == other.scanline;
|
||||
}
|
||||
|
||||
bool operator!=(const PlaneConfiguration &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
|
||||
// ImageConfiguration defines an image configuration.
|
||||
struct ImageConfiguration {
|
||||
// Image width.
|
||||
uint32_t width;
|
||||
// Image height;
|
||||
uint32_t height;
|
||||
// Image format;
|
||||
int format;
|
||||
// Configuration for each planes.
|
||||
std::vector<PlaneConfiguration> planes;
|
||||
// Number of padded bytes after the last plane.
|
||||
uint32_t padding;
|
||||
|
||||
ImageConfiguration() : width(0), height(0), format(0), padding(0) {};
|
||||
|
||||
bool operator==(const ImageConfiguration &other) const {
|
||||
return width == other.width &&
|
||||
height == other.height &&
|
||||
format == other.format &&
|
||||
planes == other.planes &&
|
||||
padding == other.padding;
|
||||
}
|
||||
|
||||
bool operator!=(const ImageConfiguration &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* StreamConfiguration defines a stream's configuration, such as its image buffer resolution, used
|
||||
* during stream configuration.
|
||||
*/
|
||||
struct StreamConfiguration {
|
||||
/*
|
||||
* Unique ID of the stream. Each stream must have an unique ID so it can be used to identify
|
||||
* the output streams of a StreamBuffer in CaptureRequest.
|
||||
*/
|
||||
uint32_t id;
|
||||
|
||||
// Image configuration.
|
||||
ImageConfiguration image;
|
||||
|
||||
bool operator==(const StreamConfiguration &other) const {
|
||||
return id == other.id &&
|
||||
image == other.image;
|
||||
}
|
||||
|
||||
bool operator!=(const StreamConfiguration &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* SensorMode contains the sensor mode information.
|
||||
*/
|
||||
struct SensorMode {
|
||||
// Usually 0 is back camera and 1 is front camera.
|
||||
uint32_t cameraId;
|
||||
|
||||
// Pixel array resolution.
|
||||
uint32_t pixelArrayWidth;
|
||||
uint32_t pixelArrayHeight;
|
||||
|
||||
// Active array resolution.
|
||||
uint32_t activeArrayWidth;
|
||||
uint32_t activeArrayHeight;
|
||||
|
||||
// Sensor output pixel clock.
|
||||
uint32_t outputPixelClkHz;
|
||||
|
||||
// Sensor timestamp offset due to gyro calibration. When comparing timestamps between AP and
|
||||
// Easel, this offset should be subtracted from AP timestamp.
|
||||
int64_t timestampOffsetNs;
|
||||
|
||||
// Sensor timestamp offset due to sensor cropping. When comparing timestamps between AP and
|
||||
// Easel, this offset should be subtracted from AP timestamp.
|
||||
int64_t timestampCropOffsetNs;
|
||||
|
||||
// Sensor output format as defined in android_pixel_format.
|
||||
int format;
|
||||
|
||||
SensorMode() : cameraId(0), pixelArrayWidth(0), pixelArrayHeight(0), activeArrayWidth(0),
|
||||
activeArrayHeight(0), outputPixelClkHz(0) {};
|
||||
};
|
||||
|
||||
/*
|
||||
* InputConfiguration defines the input configuration for HDR+ service.
|
||||
*/
|
||||
struct InputConfiguration {
|
||||
// Whether the input frames come from sensor MIPI or AP. If true, HDR+ service will get input
|
||||
// frames from sensor and sensorMode contains the sensor mode information. If false, HDR+
|
||||
// service will get input frames from AP and streamConfig contains the input stream
|
||||
// configuration.
|
||||
bool isSensorInput;
|
||||
// Sensor mode if isSensorInput is true.
|
||||
SensorMode sensorMode;
|
||||
// Input stream configuration if isSensorInput is false.
|
||||
StreamConfiguration streamConfig;
|
||||
|
||||
InputConfiguration() : isSensorInput(false) {};
|
||||
};
|
||||
|
||||
/*
|
||||
* StreamBuffer defines a buffer in a stream.
|
||||
*/
|
||||
struct StreamBuffer {
|
||||
// ID of the stream that this buffer belongs to.
|
||||
uint32_t streamId;
|
||||
// DMA buffer fd for this buffer if it's an ION buffer.
|
||||
int32_t dmaBufFd;
|
||||
// Pointer to the data of this buffer.
|
||||
void* data;
|
||||
// Size of the allocated data.
|
||||
uint32_t dataSize;
|
||||
};
|
||||
|
||||
/*
|
||||
* CaptureRequest defines a capture request that HDR+ client sends to HDR+ service.
|
||||
*/
|
||||
struct CaptureRequest {
|
||||
/*
|
||||
* ID of the capture request. Each capture request must have an unique ID. When HDR+ service
|
||||
* sends a CaptureResult to HDR+ client for this request, CaptureResult.requestId will be
|
||||
* assigned to this ID.
|
||||
*/
|
||||
uint32_t id;
|
||||
/*
|
||||
* Output buffers of the request. The buffers will be filled with captured image when HDR+
|
||||
* service sends the output buffers in CaptureResult.
|
||||
*/
|
||||
std::vector<StreamBuffer> outputBuffers;
|
||||
};
|
||||
|
||||
// Util functions used in StaticMetadata and FrameMetadata.
|
||||
namespace metadatautils {
|
||||
template<typename T>
|
||||
void appendValueToString(std::string *strOut, const char* key, T value);
|
||||
|
||||
template<typename T>
|
||||
void appendVectorOrArrayToString(std::string *strOut, T values);
|
||||
|
||||
template<typename T>
|
||||
void appendVectorOrArrayToString(std::string *strOut, const char* key, T values);
|
||||
|
||||
template<typename T, size_t SIZE>
|
||||
void appendVectorArrayToString(std::string *strOut, const char* key,
|
||||
std::vector<std::array<T, SIZE>> values);
|
||||
|
||||
template<typename T, size_t SIZE>
|
||||
void appendArrayArrayToString(std::string *strOut, const char* key,
|
||||
std::array<T, SIZE> values);
|
||||
} // namespace metadatautils
|
||||
|
||||
static const uint32_t DEBUG_PARAM_NONE = 0u;
|
||||
static const uint32_t DEBUG_PARAM_SAVE_GCAME_INPUT_METERING = (1u);
|
||||
static const uint32_t DEBUG_PARAM_SAVE_GCAME_INPUT_PAYLOAD = (1u << 1);
|
||||
static const uint32_t DEBUG_PARAM_SAVE_GCAME_TEXT = (1u << 2);
|
||||
|
||||
/*
|
||||
* StaticMetadata defines a camera device's characteristics.
|
||||
*
|
||||
* If this structure is changed, serialization in MessengerToHdrPlusService and deserialization in
|
||||
* MessengerListenerFromHdrPlusClient should also be updated.
|
||||
*/
|
||||
struct StaticMetadata {
|
||||
// The following are from Android Camera Metadata
|
||||
uint8_t flashInfoAvailable; // android.flash.info.available
|
||||
std::array<int32_t, 2> sensitivityRange; // android.sensor.info.sensitivityRange
|
||||
int32_t maxAnalogSensitivity; // android.sensor.maxAnalogSensitivity
|
||||
std::array<int32_t, 2> pixelArraySize; // android.sensor.info.pixelArraySize
|
||||
std::array<int32_t, 4> activeArraySize; // android.sensor.info.activeArraySize
|
||||
std::vector<std::array<int32_t, 4>> opticalBlackRegions; // android.sensor.opticalBlackRegions
|
||||
// android.scaler.availableStreamConfigurations
|
||||
std::vector<std::array<int32_t, 4>> availableStreamConfigurations;
|
||||
uint8_t referenceIlluminant1; // android.sensor.referenceIlluminant1
|
||||
uint8_t referenceIlluminant2; // android.sensor.referenceIlluminant2
|
||||
std::array<float, 9> calibrationTransform1; // android.sensor.calibrationTransform1
|
||||
std::array<float, 9> calibrationTransform2; // android.sensor.calibrationTransform2
|
||||
std::array<float, 9> colorTransform1; // android.sensor.colorTransform1
|
||||
std::array<float, 9> colorTransform2; // android.sensor.colorTransform2
|
||||
int32_t whiteLevel; // android.sensor.info.whiteLevel
|
||||
uint8_t colorFilterArrangement; // android.sensor.info.colorFilterArrangement
|
||||
std::vector<float> availableApertures; // android.lens.info.availableApertures
|
||||
std::vector<float> availableFocalLengths; // android.lens.info.availableFocalLengths
|
||||
std::array<int32_t, 2> shadingMapSize; // android.lens.info.shadingMapSize
|
||||
uint8_t focusDistanceCalibration; // android.lens.info.focusDistanceCalibration
|
||||
std::array<int32_t, 2> aeCompensationRange; // android.control.aeCompensationRange
|
||||
float aeCompensationStep; // android.control.aeCompensationStep
|
||||
|
||||
uint32_t debugParams; // Use HDRPLUS_DEBUG_PARAM_*
|
||||
|
||||
// Convert this static metadata to a string and append it to the specified string.
|
||||
void appendToString(std::string *strOut) const {
|
||||
if (strOut == nullptr) return;
|
||||
|
||||
metadatautils::appendValueToString(strOut, "flashInfoAvailable", flashInfoAvailable);
|
||||
metadatautils::appendVectorOrArrayToString(strOut, "sensitivityRange", sensitivityRange);
|
||||
metadatautils::appendValueToString(strOut, "maxAnalogSensitivity", maxAnalogSensitivity);
|
||||
metadatautils::appendVectorOrArrayToString(strOut, "pixelArraySize", pixelArraySize);
|
||||
metadatautils::appendVectorOrArrayToString(strOut, "activeArraySize", activeArraySize);
|
||||
metadatautils::appendVectorArrayToString(strOut, "opticalBlackRegions",
|
||||
opticalBlackRegions);
|
||||
metadatautils::appendVectorArrayToString(strOut, "availableStreamConfigurations",
|
||||
availableStreamConfigurations);
|
||||
metadatautils::appendValueToString(strOut, "referenceIlluminant1", referenceIlluminant1);
|
||||
metadatautils::appendValueToString(strOut, "referenceIlluminant2", referenceIlluminant2);
|
||||
metadatautils::appendVectorOrArrayToString(strOut, "calibrationTransform1",
|
||||
calibrationTransform1);
|
||||
metadatautils::appendVectorOrArrayToString(strOut, "calibrationTransform2",
|
||||
calibrationTransform2);
|
||||
metadatautils::appendVectorOrArrayToString(strOut, "colorTransform1", colorTransform1);
|
||||
metadatautils::appendVectorOrArrayToString(strOut, "colorTransform2", colorTransform2);
|
||||
metadatautils::appendValueToString(strOut, "whiteLevel", whiteLevel);
|
||||
metadatautils::appendValueToString(strOut, "colorFilterArrangement",
|
||||
colorFilterArrangement);
|
||||
metadatautils::appendVectorOrArrayToString(strOut, "availableApertures",
|
||||
availableApertures);
|
||||
metadatautils::appendVectorOrArrayToString(strOut, "availableFocalLengths",
|
||||
availableFocalLengths);
|
||||
metadatautils::appendVectorOrArrayToString(strOut, "shadingMapSize", shadingMapSize);
|
||||
metadatautils::appendValueToString(strOut, "focusDistanceCalibration",
|
||||
focusDistanceCalibration);
|
||||
metadatautils::appendVectorOrArrayToString(strOut, "aeCompensationRange",
|
||||
aeCompensationRange);
|
||||
metadatautils::appendValueToString(strOut, "aeCompensationStep",
|
||||
aeCompensationStep);
|
||||
metadatautils::appendValueToString(strOut, "debugParams", debugParams);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* FrameMetadata defines properties of a frame captured on AP.
|
||||
*
|
||||
* If this structure is changed, serialization in MessengerToHdrPlusService and deserialization in
|
||||
* MessengerListenerFromHdrPlusClient should also be updated.
|
||||
*/
|
||||
struct FrameMetadata {
|
||||
int64_t easelTimestamp; // Easel timestamp
|
||||
|
||||
// The following are from Android Camera Metadata
|
||||
int64_t exposureTime; // android.sensor.exposureTime
|
||||
int32_t sensitivity; // android.sensor.sensitivity
|
||||
int32_t postRawSensitivityBoost; // android.control.postRawSensitivityBoost
|
||||
uint8_t flashMode; // android.flash.mode
|
||||
std::array<float, 4> colorCorrectionGains; // android.colorCorrection.gains
|
||||
std::array<float, 9> colorCorrectionTransform; // android.colorCorrection.transform
|
||||
std::array<float, 3> neutralColorPoint; // android.sensor.neutralColorPoint
|
||||
int64_t timestamp; // android.sensor.timestamp
|
||||
uint8_t blackLevelLock; // android.blackLevel.lock
|
||||
uint8_t faceDetectMode; // android.statistics.faceDetectMode
|
||||
std::vector<int32_t> faceIds; // android.statistics.faceIds
|
||||
std::vector<std::array<int32_t, 6>> faceLandmarks; // android.statistics.faceLandmarks
|
||||
std::vector<std::array<int32_t, 4>> faceRectangles; // android.statistics.faceRectangles
|
||||
std::vector<uint8_t> faceScores; // android.statistics.faceScores
|
||||
uint8_t sceneFlicker; // android.statistics.sceneFlicker
|
||||
std::array<std::array<double, 2>, 4> noiseProfile; // android.sensor.noiseProfile
|
||||
std::array<float, 4> dynamicBlackLevel; // android.sensor.dynamicBlackLevel
|
||||
std::vector<float> lensShadingMap; // android.statistics.lensShadingMap
|
||||
float focusDistance; // android.lens.focusDistance
|
||||
int32_t aeExposureCompensation; // android.control.aeExposureCompensation
|
||||
uint8_t aeMode; // android.control.aeMode
|
||||
uint8_t aeLock; // android.control.aeLock
|
||||
uint8_t aeState; // android.control.aeState
|
||||
uint8_t aePrecaptureTrigger; // android.control.aePrecaptureTrigger
|
||||
std::vector<std::array<int32_t, 5>> aeRegions; // android.control.aeRegions
|
||||
|
||||
// Convert this static metadata to a string and append it to the specified string.
|
||||
void appendToString(std::string *strOut) const {
|
||||
if (strOut == nullptr) return;
|
||||
|
||||
metadatautils::appendValueToString(strOut, "easelTimestamp", easelTimestamp);
|
||||
metadatautils::appendValueToString(strOut, "exposureTime", exposureTime);
|
||||
metadatautils::appendValueToString(strOut, "sensitivity", sensitivity);
|
||||
metadatautils::appendValueToString(strOut, "postRawSensitivityBoost",
|
||||
postRawSensitivityBoost);
|
||||
metadatautils::appendValueToString(strOut, "flashMode", flashMode);
|
||||
metadatautils::appendVectorOrArrayToString(strOut, "colorCorrectionGains",
|
||||
colorCorrectionGains);
|
||||
metadatautils::appendVectorOrArrayToString(strOut, "colorCorrectionTransform",
|
||||
colorCorrectionTransform);
|
||||
metadatautils::appendVectorOrArrayToString(strOut, "neutralColorPoint", neutralColorPoint);
|
||||
metadatautils::appendValueToString(strOut, "timestamp", timestamp);
|
||||
metadatautils::appendValueToString(strOut, "blackLevelLock", blackLevelLock);
|
||||
metadatautils::appendValueToString(strOut, "faceDetectMode", faceDetectMode);
|
||||
metadatautils::appendVectorOrArrayToString(strOut, "faceIds", faceIds);
|
||||
metadatautils::appendVectorArrayToString(strOut, "faceLandmarks", faceLandmarks);
|
||||
metadatautils::appendVectorArrayToString(strOut, "faceRectangles", faceRectangles);
|
||||
metadatautils::appendVectorOrArrayToString(strOut, "faceScores", faceScores);
|
||||
metadatautils::appendArrayArrayToString(strOut, "noiseProfile", noiseProfile);
|
||||
metadatautils::appendValueToString(strOut, "sceneFlicker", sceneFlicker);
|
||||
metadatautils::appendVectorOrArrayToString(strOut, "dynamicBlackLevel", dynamicBlackLevel);
|
||||
metadatautils::appendVectorOrArrayToString(strOut, "lensShadingMap", lensShadingMap);
|
||||
metadatautils::appendValueToString(strOut, "focusDistance", focusDistance);
|
||||
metadatautils::appendValueToString(strOut, "aeExposureCompensation", aeExposureCompensation);
|
||||
metadatautils::appendValueToString(strOut, "aeMode", aeMode);
|
||||
metadatautils::appendValueToString(strOut, "aeLock", aeLock);
|
||||
metadatautils::appendValueToString(strOut, "aeState", aeState);
|
||||
metadatautils::appendValueToString(strOut, "aePrecaptureTrigger", aePrecaptureTrigger);
|
||||
metadatautils::appendVectorArrayToString(strOut, "aeRegions", aeRegions);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* RequestMetadata defines the properties for a capture request.
|
||||
*
|
||||
* If this structure is changed, serialization in MessengerToHdrPlusClient and deserialization in
|
||||
* MessengerListenerFromHdrPlusService should also be updated.
|
||||
*/
|
||||
struct RequestMetadata {
|
||||
std::array<int32_t, 4> cropRegion; // android.scaler.cropRegion (x_min, y_min, width, height)
|
||||
int32_t aeExposureCompensation; // android.control.aeExposureCompensation
|
||||
|
||||
bool postviewEnable; // com.google.nexus.experimental2017.stats.postview_enable
|
||||
bool continuousCapturing; // Whether to capture RAW while HDR+ processing.
|
||||
|
||||
// Convert this static metadata to a string and append it to the specified string.
|
||||
void appendToString(std::string *strOut) const {
|
||||
if (strOut == nullptr) return;
|
||||
metadatautils::appendVectorOrArrayToString(strOut, "cropRegion", cropRegion);
|
||||
metadatautils::appendValueToString(strOut, "aeExposureCompensation", aeExposureCompensation);
|
||||
metadatautils::appendValueToString(strOut, "postviewEnable", postviewEnable);
|
||||
metadatautils::appendValueToString(strOut, "continuousCapturing", continuousCapturing);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* ResultMetadata defines a process frame's properties that have been modified due to processing.
|
||||
*
|
||||
* If this structure is changed, serialization in MessengerToHdrPlusClient and deserialization in
|
||||
* MessengerListenerFromHdrPlusService should also be updated.
|
||||
*/
|
||||
struct ResultMetadata {
|
||||
int64_t easelTimestamp; // Easel timestamp of SOF of the base frame.
|
||||
int64_t timestamp; // android.sensor.timestamp. AP timestamp of exposure start of the base
|
||||
// frame.
|
||||
std::string makernote; // Obfuscated capture information.
|
||||
|
||||
// Convert this static metadata to a string and append it to the specified string.
|
||||
void appendToString(std::string *strOut) const {
|
||||
if (strOut == nullptr) return;
|
||||
metadatautils::appendValueToString(strOut, "easelTimestamp", easelTimestamp);
|
||||
metadatautils::appendValueToString(strOut, "timestamp", timestamp);
|
||||
metadatautils::appendValueToString(strOut, "makernote", makernote.size());
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* CaptureResult defines a capture result that HDR+ service returns to HDR+ client.
|
||||
*/
|
||||
struct CaptureResult {
|
||||
/*
|
||||
* ID of the CaptureRequest that this capture result corresponds to. It can be used to match
|
||||
* the original CaptureRequest when the HDR+ client receives this result.
|
||||
*/
|
||||
uint32_t requestId;
|
||||
/*
|
||||
* Output buffers filled with processed frame by HDR+ service.
|
||||
*/
|
||||
std::vector<StreamBuffer> outputBuffers;
|
||||
|
||||
/*
|
||||
* Result metadata including modified properties due to processing.
|
||||
*/
|
||||
ResultMetadata metadata;
|
||||
};
|
||||
|
||||
// Util functions used in StaticMetadata and FrameMetadata.
|
||||
namespace metadatautils {
|
||||
|
||||
/*
|
||||
* Append a key and a value to a string.
|
||||
*
|
||||
* strOut is the string to append a key and a value to.
|
||||
* key is the name of the data.
|
||||
* value is the value of the data.
|
||||
*/
|
||||
template<typename T>
|
||||
void appendValueToString(std::string *strOut, const char* key, T value) {
|
||||
if (strOut == nullptr) return;
|
||||
(*strOut) += std::string(key) + ": " + std::to_string(value) + "\n";
|
||||
}
|
||||
|
||||
/*
|
||||
* Append a vector or an array of values to a string.
|
||||
*
|
||||
* strOut is the string to append a key and values to.
|
||||
* values is a vector or an array containing values to append to the string.
|
||||
*/
|
||||
template<typename T>
|
||||
void appendVectorOrArrayToString(std::string *strOut, T values) {
|
||||
if (strOut == nullptr) return;
|
||||
for (size_t i = 0; i < values.size(); i++) {
|
||||
(*strOut) += std::to_string(values[i]);
|
||||
if (i != values.size() - 1) {
|
||||
(*strOut) +=", ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Append a key and a vector or an array of values to a string.
|
||||
*
|
||||
* strOut is the string to append a key and values to.
|
||||
* key is the name of the data.
|
||||
* values is a vector or an array containing values to append to the string.
|
||||
*/
|
||||
template<typename T>
|
||||
void appendVectorOrArrayToString(std::string *strOut, const char* key, T values) {
|
||||
if (strOut == nullptr) return;
|
||||
(*strOut) += std::string(key) + ": ";
|
||||
appendVectorOrArrayToString(strOut, values);
|
||||
(*strOut) += "\n";
|
||||
}
|
||||
|
||||
/*
|
||||
* Append a key and a vector of arrays to a string.
|
||||
*
|
||||
* strOut is the string to append a key and values to.
|
||||
* key is the name of the data.
|
||||
* values is a vector of arrays containing values to append to the string.
|
||||
*/
|
||||
template<typename T, size_t SIZE>
|
||||
void appendVectorArrayToString(std::string *strOut, const char* key,
|
||||
std::vector<std::array<T, SIZE>> values) {
|
||||
if (strOut == nullptr) return;
|
||||
(*strOut) += std::string(key) + ": ";
|
||||
for (size_t i = 0; i < values.size(); i++) {
|
||||
appendVectorOrArrayToString(strOut, values[i]);
|
||||
if (i != values.size() - 1) {
|
||||
(*strOut) +=", ";
|
||||
}
|
||||
}
|
||||
(*strOut) += "\n";
|
||||
}
|
||||
|
||||
/*
|
||||
* Append a key and an array of arrays to a string.
|
||||
*
|
||||
* strOut is the string to append a key and values to.
|
||||
* key is the name of the data.
|
||||
* values is an array of arrays containing values to append to the string.
|
||||
*/
|
||||
template<typename T, size_t SIZE>
|
||||
void appendArrayArrayToString(std::string *strOut, const char* key,
|
||||
std::array<T, SIZE> values) {
|
||||
if (strOut == nullptr) return;
|
||||
(*strOut) += std::string(key) + ": ";
|
||||
for (size_t i = 0; i < values.size(); i++) {
|
||||
appendVectorOrArrayToString(strOut, values[i]);
|
||||
if (i != values.size() - 1) {
|
||||
(*strOut) +=", ";
|
||||
}
|
||||
}
|
||||
(*strOut) += "\n";
|
||||
}
|
||||
|
||||
} // namespace metadatautils
|
||||
|
||||
} // namespace pbcamera
|
||||
|
||||
#endif // HDR_PLUS_TYPES_H
|
|
@ -0,0 +1,56 @@
|
|||
# Copyright 2016 The Android Open Source Project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
|
||||
#
|
||||
# libhdrplusclient
|
||||
#
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
EaselManagerClient.cpp \
|
||||
HdrPlusClientUtils.cpp
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := liblog
|
||||
|
||||
# For AOSP builds, use dummy implementation.
|
||||
ifeq ($(wildcard vendor/google_easel),)
|
||||
LOCAL_CFLAGS += -DUSE_DUMMY_IMPL=1
|
||||
else
|
||||
LOCAL_CFLAGS += -DUSE_DUMMY_IMPL=0
|
||||
LOCAL_SHARED_LIBRARIES += libhdrplusclientimpl
|
||||
endif
|
||||
|
||||
LOCAL_HEADER_LIBRARIES := \
|
||||
libsystem_headers \
|
||||
libutils_headers
|
||||
LOCAL_EXPORT_HEADER_LIBRARY_HEADERS := \
|
||||
libutils_headers
|
||||
|
||||
LOCAL_C_INCLUDES += \
|
||||
$(LOCAL_PATH)/include \
|
||||
hardware/google/easel/camera/include
|
||||
|
||||
LOCAL_CFLAGS += -Wall -Wextra -Werror
|
||||
|
||||
LOCAL_EXPORT_C_INCLUDE_DIRS += \
|
||||
$(LOCAL_PATH)/include \
|
||||
hardware/google/easel/camera/include
|
||||
|
||||
LOCAL_MODULE:= libhdrplusclient
|
||||
LOCAL_PROPRIETARY_MODULE := true
|
||||
LOCAL_MODULE_OWNER := google
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#define LOG_TAG "EaselManagerClient"
|
||||
#include <log/log.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "EaselManagerClient.h"
|
||||
|
||||
#if !USE_DUMMY_IMPL
|
||||
#include "EaselManagerClientImpl.h"
|
||||
#endif
|
||||
|
||||
namespace android {
|
||||
|
||||
std::unique_ptr<EaselManagerClient> EaselManagerClient::create() {
|
||||
#if USE_DUMMY_IMPL
|
||||
return nullptr;
|
||||
#else
|
||||
return std::make_unique<EaselManagerClientImpl>();
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace android
|
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
* Copyright 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//#define LOG_NDEBUG 0
|
||||
#define LOG_TAG "HdrPlusClientUtils"
|
||||
#include <log/log.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <inttypes.h>
|
||||
#include <system/graphics.h>
|
||||
|
||||
#include "HdrPlusClientUtils.h"
|
||||
|
||||
namespace android {
|
||||
namespace hdrplus_client_utils {
|
||||
|
||||
// Get the RGB values of the pixel at (x, y).
|
||||
static status_t getRgb(uint8_t *r, uint8_t *g, uint8_t* b, uint32_t x, uint32_t y,
|
||||
const pbcamera::StreamConfiguration &streamConfig,
|
||||
const pbcamera::StreamBuffer &buffer) {
|
||||
switch (streamConfig.image.format) {
|
||||
case HAL_PIXEL_FORMAT_YCrCb_420_SP:
|
||||
{
|
||||
// Check the stream configuration has two planes.
|
||||
if (streamConfig.image.planes.size() != 2) {
|
||||
ALOGE("%s: NV21 should have 2 planes but it has %zu", __FUNCTION__,
|
||||
streamConfig.image.planes.size());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
// Find the indices of Y, V, and U in the buffer.
|
||||
uint32_t yIndex = y * streamConfig.image.planes[0].stride + x;
|
||||
uint32_t vIndex = streamConfig.image.planes[0].scanline *
|
||||
streamConfig.image.planes[0].stride +
|
||||
(y / 2) * streamConfig.image.planes[1].stride + (x & ~0x1);
|
||||
uint32_t uIndex = vIndex + 1;
|
||||
|
||||
// Convert YUV to RGB.
|
||||
int32_t yc = ((uint8_t*)buffer.data)[yIndex];
|
||||
int32_t vc = ((uint8_t*)buffer.data)[vIndex] - 128;
|
||||
int32_t uc = ((uint8_t*)buffer.data)[uIndex] - 128;
|
||||
*r = std::min(std::max(yc + 0.003036f * uc + 1.399457f * vc, 0.0f), 255.0f);
|
||||
*g = std::min(std::max(yc - 0.344228f * uc - 0.717202f * vc, 0.0f), 255.0f);
|
||||
*b = std::min(std::max(yc + 1.772431f * uc - 0.006137f * vc, 0.0f), 255.0f);
|
||||
return OK;
|
||||
}
|
||||
case HAL_PIXEL_FORMAT_RGB_888:
|
||||
{
|
||||
// Check the stream configuration has 1 plane.
|
||||
if (streamConfig.image.planes.size() != 1) {
|
||||
ALOGE("%s: RGB_888 should have 1 plane but it has %zu", __FUNCTION__,
|
||||
streamConfig.image.planes.size());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
uint32_t offset = y * streamConfig.image.planes[0].stride + x * 3;
|
||||
*r = ((uint8_t*)buffer.data)[offset];
|
||||
*g = ((uint8_t*)buffer.data)[offset + 1];
|
||||
*b = ((uint8_t*)buffer.data)[offset + 2];
|
||||
return OK;
|
||||
}
|
||||
default:
|
||||
ALOGE("%s: Format %d is not supported.", __FUNCTION__, streamConfig.image.format);
|
||||
return BAD_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
status_t writePpm(const std::string &filename, const pbcamera::StreamConfiguration &streamConfig,
|
||||
const pbcamera::StreamBuffer &buffer) {
|
||||
if (streamConfig.image.format != HAL_PIXEL_FORMAT_YCrCb_420_SP &&
|
||||
streamConfig.image.format != HAL_PIXEL_FORMAT_RGB_888) {
|
||||
ALOGE("%s: format 0x%x is not supported.", __FUNCTION__, streamConfig.image.format);
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
std::ofstream outfile(filename, std::ios::binary);
|
||||
if (!outfile.is_open()) {
|
||||
ALOGE("%s: Opening file (%s) failed.", __FUNCTION__, filename.data());
|
||||
return NO_INIT;
|
||||
}
|
||||
|
||||
uint32_t width = streamConfig.image.width;
|
||||
uint32_t height = streamConfig.image.height;
|
||||
|
||||
// Write headers of the ppm file.
|
||||
outfile << "P6";
|
||||
outfile << " " << std::to_string(width) << " " << std::to_string(height) << " 255 ";
|
||||
|
||||
// Write RGB values of the image.
|
||||
uint8_t r, g, b;
|
||||
for (uint32_t y = 0; y < height; y++) {
|
||||
for (uint32_t x = 0; x < width; x++) {
|
||||
status_t res = getRgb(&r, &g, &b, x, y, streamConfig, buffer);
|
||||
if (res != OK) {
|
||||
ALOGE("%s: Getting RGB failed: %s (%d).", __FUNCTION__, strerror(-res), res);
|
||||
return res;
|
||||
}
|
||||
outfile << r << g << b;
|
||||
}
|
||||
}
|
||||
|
||||
ALOGD("%s: Saved file: %s", __FUNCTION__, filename.data());
|
||||
|
||||
outfile.close();
|
||||
return OK;
|
||||
}
|
||||
|
||||
status_t comparePpm(const std::string &filename, const pbcamera::StreamConfiguration &streamConfig,
|
||||
const pbcamera::StreamBuffer &buffer, float *diffRatio) {
|
||||
if (streamConfig.image.format != HAL_PIXEL_FORMAT_YCrCb_420_SP) {
|
||||
ALOGE("%s: format 0x%x is not supported.", __FUNCTION__, streamConfig.image.format);
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
std::ifstream ifile(filename, std::ios::binary);
|
||||
if (!ifile.is_open()) {
|
||||
ALOGE("%s: Opening file (%s) failed.", __FUNCTION__, filename.data());
|
||||
return NO_INIT;
|
||||
}
|
||||
|
||||
std::string s;
|
||||
|
||||
// Read headers of the ppm file.
|
||||
ifile >> s;
|
||||
if (s != "P6") {
|
||||
ALOGE("%s: Invalid PPM file header: %s", __FUNCTION__, s.c_str());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
// Read width and height.
|
||||
ifile >> s;
|
||||
uint32_t width = std::stoul(s);
|
||||
|
||||
ifile >> s;
|
||||
uint32_t height = std::stoul(s);
|
||||
|
||||
if (width != streamConfig.image.width || height != streamConfig.image.height) {
|
||||
ALOGE("%s: Image resolution doesn't match. image %dx%d ppm %dx%d",
|
||||
__FUNCTION__, streamConfig.image.width, streamConfig.image.height,
|
||||
width, height);
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
ifile >> s;
|
||||
if (s != "255") {
|
||||
ALOGE("%s: Expecting 255 but got %s", __FUNCTION__, s.c_str());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
char c;
|
||||
|
||||
// Get a space
|
||||
ifile.get(c);
|
||||
|
||||
// Now the RGB values start.
|
||||
uint8_t r, g, b;
|
||||
uint64_t diff = 0;
|
||||
|
||||
for (uint32_t y = 0; y < height; y++) {
|
||||
for (uint32_t x = 0; x < width; x++) {
|
||||
status_t res = getRgb(&r, &g, &b, x, y, streamConfig, buffer);
|
||||
if (res != OK) {
|
||||
ALOGE("%s: Getting RGB failed: %s (%d).", __FUNCTION__, strerror(-res), res);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Get r, g, b from golden image and accumulate the differences.
|
||||
ifile.get(c);
|
||||
diff += abs(static_cast<int32_t>(c) - r);
|
||||
ifile.get(c);
|
||||
diff += abs(static_cast<int32_t>(c) - g);
|
||||
ifile.get(c);
|
||||
diff += abs(static_cast<int32_t>(c) - b);
|
||||
}
|
||||
}
|
||||
|
||||
if (diffRatio != nullptr) {
|
||||
*diffRatio = diff / (static_cast<float>(width) * height * 3 * 256);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
} // hdrplus_client_utils
|
||||
} // namespace android
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* Copyright 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef EASEL_MANAGER_CLIENT_H
|
||||
#define EASEL_MANAGER_CLIENT_H
|
||||
|
||||
#include <future>
|
||||
|
||||
#include <utils/Errors.h>
|
||||
#include <utils/Mutex.h>
|
||||
|
||||
#define FW_VER_SIZE 24
|
||||
|
||||
namespace android {
|
||||
|
||||
class EaselManagerClientListener;
|
||||
class HdrPlusClient;
|
||||
class HdrPlusClientListener;
|
||||
|
||||
class EaselManagerClient {
|
||||
public:
|
||||
static std::unique_ptr<EaselManagerClient> create();
|
||||
|
||||
EaselManagerClient() {};
|
||||
virtual ~EaselManagerClient() {};
|
||||
|
||||
/*
|
||||
* Return if Easel is present on the device.
|
||||
*
|
||||
* If Easel is not present, all other calls to HdrPlusClient are invalid.
|
||||
*/
|
||||
virtual bool isEaselPresentOnDevice() const = 0;
|
||||
|
||||
/*
|
||||
* Open Easel manager client.
|
||||
*
|
||||
* This will power on Easel and initialize Easel manager client.
|
||||
*/
|
||||
virtual status_t open() = 0;
|
||||
|
||||
/*
|
||||
* Suspend Easel.
|
||||
*
|
||||
* Put Easel on suspend mode.
|
||||
*/
|
||||
virtual status_t suspend() = 0;
|
||||
|
||||
/*
|
||||
* Resume Easel.
|
||||
*
|
||||
* Resume Easel from suspend mode.
|
||||
*
|
||||
* listener will be invoked for Easel status.
|
||||
*/
|
||||
virtual status_t resume(EaselManagerClientListener *listener) = 0;
|
||||
|
||||
/*
|
||||
* Retrieve Easel firmware version.
|
||||
*
|
||||
* Firmware version string is added to image exif
|
||||
*/
|
||||
virtual status_t getFwVersion(char *fwVersion) = 0;
|
||||
|
||||
/*
|
||||
* Start MIPI with an output pixel lock rate for a camera.
|
||||
*
|
||||
* Can be called when Easel is powered on or resumed, for Easel to start sending sensor data
|
||||
* to AP.
|
||||
*
|
||||
* cameraId is the camera ID to start MIPI for.
|
||||
* outputPixelClkHz is the output pixel rate.
|
||||
* enableCapture is whether to enable MIPI capture on Easel.
|
||||
*/
|
||||
virtual status_t startMipi(uint32_t cameraId, uint32_t outputPixelClkHz,
|
||||
bool enableCapture) = 0;
|
||||
|
||||
/*
|
||||
* Stop MIPI for a camera.
|
||||
*
|
||||
* cameraId is the camera is ID to stop MIPI for.
|
||||
*/
|
||||
virtual status_t stopMipi(uint32_t cameraId) = 0;
|
||||
|
||||
/*
|
||||
* Open an HDR+ client asynchronously.
|
||||
*
|
||||
* Open an HDR+ client asynchronouly. When an HDR+ client is opened,
|
||||
* HdrPlusClientListener::onOpened() will be invoked with the created HDR+ client. If opening
|
||||
* an HDR+ client failed, HdrPlusClientListener::onOpenFailed() will be invoked with the error.
|
||||
* If this method returns an error, HdrPlusClientListener::onOpenFailed() will not be invoked.
|
||||
*
|
||||
* listener is an HDR+ client listener.
|
||||
*
|
||||
* Returns:
|
||||
* OK: if initiating opening an HDR+ client asynchronously was successful.
|
||||
* HdrPlusClientListener::onOpened() or HdrPlusClientListener::onOpenFailed()
|
||||
* will be invoked when opening an HDR+ client completed.
|
||||
* ALREADY_EXISTS: if there is already a pending HDR+ client being opened.
|
||||
*/
|
||||
virtual status_t openHdrPlusClientAsync(HdrPlusClientListener *listener) = 0;
|
||||
|
||||
/*
|
||||
* Open an HDR+ client synchronously and block until it completes.
|
||||
*
|
||||
* listener is an HDR+ client listener.
|
||||
* client is an output parameter for created HDR+ client.
|
||||
*
|
||||
* Returns:
|
||||
* OK: on success.
|
||||
* -EEXIST: if an HDR+ client is already opened.
|
||||
* -ENODEV: if opening an HDR+ failed due to a serious error.
|
||||
*/
|
||||
virtual status_t openHdrPlusClient(HdrPlusClientListener *listener,
|
||||
std::unique_ptr<HdrPlusClient> *client) = 0;
|
||||
|
||||
/*
|
||||
* Close an HDR+ client.
|
||||
*
|
||||
* client is the HDR+ client to be closed.
|
||||
*/
|
||||
virtual void closeHdrPlusClient(std::unique_ptr<HdrPlusClient> client) = 0;
|
||||
|
||||
private:
|
||||
// Disallow copy and assign.
|
||||
EaselManagerClient(const EaselManagerClient&) = delete;
|
||||
void operator=(const EaselManagerClient&) = delete;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* EaselManagerClientListener defines callbacks that will be invoked by EaselManagerClient.
|
||||
*/
|
||||
class EaselManagerClientListener {
|
||||
public:
|
||||
virtual ~EaselManagerClientListener() {};
|
||||
|
||||
// Invoked when Easel encountered a fatal error. Client should shut down Easel.
|
||||
virtual void onEaselFatalError(std::string errMsg) = 0;
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
||||
#endif // EASEL_MANAGER_CLIENT_H
|
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
* Copyright 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef HDR_PLUS_CLIENT_H
|
||||
#define HDR_PLUS_CLIENT_H
|
||||
|
||||
#include "CameraMetadata.h"
|
||||
#include "hardware/camera3.h"
|
||||
#include "HdrPlusClientListener.h"
|
||||
#include "HdrPlusTypes.h"
|
||||
|
||||
using ::android::hardware::camera::common::V1_0::helper::CameraMetadata;
|
||||
namespace android {
|
||||
|
||||
/**
|
||||
* HdrPlusClient
|
||||
*
|
||||
* HdrPlusClient class can be used to connect to HDR+ service to perform HDR+ processing on
|
||||
* Easel.
|
||||
*/
|
||||
class HdrPlusClient {
|
||||
public:
|
||||
// HdrPlusClientListener is the listener to receive callbacks from HDR+ client. The listener
|
||||
// must be valid during the life cycle of HdrPlusClient
|
||||
HdrPlusClient(HdrPlusClientListener *) {};
|
||||
/*
|
||||
* The recommended way to create an HdrPlusClient instance is via
|
||||
* EaselManagerClient::openHdrPlusClientAsync() or EaselManagerClient::openHdrPlusClientAsync().
|
||||
* EaselManagerClient will make sure Easel is in a valid state to open an HDR+ client. To close
|
||||
* an HdrPlusClient, use EaselManagerClient::closeHdrPlusClient.
|
||||
*/
|
||||
virtual ~HdrPlusClient() {};
|
||||
|
||||
/*
|
||||
* Connect to HDR+ service.
|
||||
*
|
||||
* If EaselManagerClient is used to create the HdrPlusClient, it is already connected.
|
||||
*
|
||||
* Returns:
|
||||
* 0: on success.
|
||||
* -EEXIST: if it's already connected.
|
||||
* -ENODEV: if connecting failed due to a serious error.
|
||||
*/
|
||||
virtual status_t connect() = 0;
|
||||
|
||||
/*
|
||||
* Set the static metadata of current camera device.
|
||||
*
|
||||
* Must be called after connect() and before configuring streams.
|
||||
*
|
||||
* staticMetadata is the static metadata of current camera device.
|
||||
*
|
||||
* Returns:
|
||||
* 0: on success.
|
||||
* -ENODEV: if HDR+ service is not connected.
|
||||
*/
|
||||
virtual status_t setStaticMetadata(const camera_metadata_t &staticMetadata) = 0;
|
||||
|
||||
/*
|
||||
* Configure streams.
|
||||
*
|
||||
* Must be called when configuration changes including input (sensor) resolution and format, and
|
||||
* output resolutions and formats.
|
||||
*
|
||||
* inputConfig contains the information about the input frames or sensor configurations.
|
||||
* outputConfigs is a vector of output stream configurations.
|
||||
*
|
||||
* Returns:
|
||||
* 0: on success.
|
||||
* -EINVAL: if outputConfigs is empty or the configurations are not supported.
|
||||
* -ENODEV: if HDR+ service is not connected.
|
||||
*/
|
||||
virtual status_t configureStreams(const pbcamera::InputConfiguration &inputConfig,
|
||||
const std::vector<pbcamera::StreamConfiguration> &outputConfigs) = 0;
|
||||
|
||||
/*
|
||||
* Enable or disable ZSL HDR+ mode.
|
||||
*
|
||||
* When ZSL HDR+ mode is enabled, Easel will capture ZSL RAW buffers. ZSL HDR+ mode should be
|
||||
* disabled to reduce power consumption when HDR+ processing is not necessary, e.g in video
|
||||
* mode.
|
||||
*
|
||||
* enabled is a flag indicating whether to enable ZSL HDR+ mode.
|
||||
*
|
||||
* Returns:
|
||||
* 0: on success.
|
||||
* -ENODEV: if HDR+ service is not connected, or streams are not configured.
|
||||
*/
|
||||
virtual status_t setZslHdrPlusMode(bool enabled) = 0;
|
||||
|
||||
/*
|
||||
* Submit a capture request for HDR+ outputs.
|
||||
*
|
||||
* For each output buffer in CaptureRequest, it will be returned in a CaptureResult via
|
||||
* HdrPlusClientListener::onCaptureResult(). HdrPlusClientListener::onCaptureResult() may be
|
||||
* invoked multiple times to return all output buffers in one CaptureRequest. Each output
|
||||
* buffer will be returned in CaptureResult only once.
|
||||
*
|
||||
* request is a CaptureRequest containing output buffers to be filled by HDR+ service.
|
||||
* requestMetadata is the metadata for this request.
|
||||
*
|
||||
* Returns:
|
||||
* 0: on success.
|
||||
* -EINVAL: if the request is invalid such as containing invalid stream IDs.
|
||||
*/
|
||||
virtual status_t submitCaptureRequest(pbcamera::CaptureRequest *request,
|
||||
const CameraMetadata &requestMetadata) = 0;
|
||||
|
||||
/*
|
||||
* Send an input buffer to HDR+ service. This is used when HDR+ service's input buffers come
|
||||
* from the client rather than MIPI.
|
||||
*
|
||||
* inputBuffer is the input buffer to send to HDR+ service. After this method returns, the
|
||||
* buffer has been copied (with DMA) to HDR+ service and the caller has the
|
||||
* ownership of the buffer.
|
||||
*/
|
||||
virtual void notifyInputBuffer(const pbcamera::StreamBuffer &inputBuffer,
|
||||
int64_t timestampNs) = 0;
|
||||
|
||||
/*
|
||||
* Notify about result metadata of a frame that AP captured. This may be called multiple times
|
||||
* for a frame to send multiple partial metadata and lastMetadata must be false except for the
|
||||
* last partial metadata. When there is only one metadata for a frame, lastMetadata must be
|
||||
* true.
|
||||
*
|
||||
* frameNumber is a unique frame number that the metadata belong to.
|
||||
* resultMetadata is the result metadata of a frame that AP captured.
|
||||
* lastMetadata is a flag indicating whether this is the last metadata for the frame number.
|
||||
*/
|
||||
virtual void notifyFrameMetadata(uint32_t frameNumber, const camera_metadata_t &resultMetadata,
|
||||
bool lastMetadata=true) = 0;
|
||||
|
||||
/*
|
||||
* Notify Easel has encountered a fatal error and HDR+ client should stop sending messages
|
||||
* to Easel.
|
||||
*/
|
||||
virtual void nofityEaselFatalError() = 0;
|
||||
|
||||
private:
|
||||
// Disallow copy and assign.
|
||||
HdrPlusClient(const HdrPlusClient&) = delete;
|
||||
void operator=(const HdrPlusClient&) = delete;
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
||||
#endif // HDR_PLUS_CLIENT_H
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef HDR_PLUS_CLIENT_LISTENER_H
|
||||
#define HDR_PLUS_CLIENT_LISTENER_H
|
||||
|
||||
#include "hardware/camera3.h"
|
||||
#include "HdrPlusTypes.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
|
||||
class HdrPlusClient;
|
||||
|
||||
/*
|
||||
* HdrPlusClientListener defines callbacks that will be invoked by HdrPlusClient for events like
|
||||
* returning capture results.
|
||||
*/
|
||||
class HdrPlusClientListener {
|
||||
public:
|
||||
virtual ~HdrPlusClientListener() {};
|
||||
|
||||
/*
|
||||
* Invoked when an HDR+ client is opened successfully via
|
||||
* EaselManagerClient::openHdrPlusClientAsync.
|
||||
*/
|
||||
virtual void onOpened(std::unique_ptr<HdrPlusClient> client) = 0;
|
||||
|
||||
/*
|
||||
* Invoked when opening an HDR+ client failed via EaselManagerClient::openHdrPlusClientAsync.
|
||||
*
|
||||
* err is
|
||||
* -EEXIST: if an HDR+ client is already opened.
|
||||
* -ENODEV: if opening an HDR+ failed due to a serious error.
|
||||
*/
|
||||
virtual void onOpenFailed(status_t err) = 0;
|
||||
|
||||
/*
|
||||
* Invoked when HDR+ client is in a fatal error state. After receiving this error, calls to HDR+
|
||||
* client will not succeed and HDR+ client should be closed.
|
||||
*/
|
||||
virtual void onFatalError() = 0;
|
||||
|
||||
/*
|
||||
* Invoked when a CaptureResult, containing a subset or all output buffers for a CaptureRequest,
|
||||
* is received. This may be invoked multiple times for one CaptureRequest but each CaptureResult
|
||||
* will contain distinct output buffers that have not been received yet.
|
||||
*/
|
||||
virtual void onCaptureResult(pbcamera::CaptureResult *result,
|
||||
const camera_metadata_t &resultMetadata) = 0;
|
||||
|
||||
/*
|
||||
* Invoked when a failed CaptureResult, containing a subset or all output buffers for a
|
||||
* CaptureRequest, is received. Output buffers in a failed capture result may contain garbage
|
||||
* data. This may be invoked multiple times for one CaptureRequest but each CaptureResult
|
||||
* will contain distinct output buffers that have not been received yet.
|
||||
*/
|
||||
virtual void onFailedCaptureResult(pbcamera::CaptureResult *failedResult) = 0;
|
||||
|
||||
/*
|
||||
* Invoked when HDR+ processing has started for a request. requestId is the ID of the request.
|
||||
* apSensorTimestampNs is the AP sensor timestamp of the base frame, in nanoseconds.
|
||||
*/
|
||||
virtual void onShutter(uint32_t requestId, int64_t apSensorTimestampNs) = 0;
|
||||
|
||||
/*
|
||||
* Invoked when Easel is ready to take another HDR+ request.
|
||||
*/
|
||||
virtual void onNextCaptureReady(uint32_t requestId) = 0;
|
||||
|
||||
/*
|
||||
* Invoked when the postview for a request is ready.
|
||||
*/
|
||||
virtual void onPostview(uint32_t requestId, std::unique_ptr<std::vector<uint8_t>> postview,
|
||||
uint32_t width, uint32_t height, uint32_t stride, int32_t format) = 0;
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
||||
#endif // HDR_PLUS_CLIENT_LISTENER_H
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef HDR_PLUS_CLIENT_UTILS_H
|
||||
#define HDR_PLUS_CLIENT_UTILS_H
|
||||
|
||||
#include <utils/Errors.h>
|
||||
|
||||
#include "HdrPlusTypes.h"
|
||||
|
||||
namespace android {
|
||||
namespace hdrplus_client_utils {
|
||||
|
||||
/*
|
||||
* Write the image buffer to a .ppm file.
|
||||
*
|
||||
* filename is the filename of the .ppm file and should include ".ppm" in the end.
|
||||
* streamConfig is the stream configuration of the buffer.
|
||||
* buffer is the buffer to be saved to a .ppm file.
|
||||
*
|
||||
* Returns
|
||||
* OK: if the file is saved successfully.
|
||||
* BAD_VALUE: if the format is not support or the stream configuration is invalid.
|
||||
* NO_INIT: if it failed to open the file.
|
||||
*/
|
||||
status_t writePpm(const std::string &filename, const pbcamera::StreamConfiguration &streamConfig,
|
||||
const pbcamera::StreamBuffer &buffer);
|
||||
|
||||
/*
|
||||
* Compare the image buffer against a golden .ppm file.
|
||||
*
|
||||
* filename is the filename of the .ppm file and should include ".ppm" in the end.
|
||||
* streamConfig is the stream configuration of the buffer.
|
||||
* buffer is the buffer to be compared.
|
||||
* diffRatio will be the difference ratio between the image buffer and the golden ppm file.
|
||||
* It's calculated as sum(R, G, B diffs in each pixel) / (width * height * 256 * 3)
|
||||
*
|
||||
* Returns
|
||||
* OK: if the comparison completed successfully.
|
||||
* BAD_VALUE: if the format is not support or the stream configuration is invalid, or the
|
||||
* file cannot be parsed correctly.
|
||||
* NO_INIT: if it failed to open the file.
|
||||
*/
|
||||
status_t comparePpm(const std::string &filename, const pbcamera::StreamConfiguration &streamConfig,
|
||||
const pbcamera::StreamBuffer &buffer, float *diffRatio);
|
||||
|
||||
} // hdrplus_client_utils
|
||||
} // namespace android
|
||||
|
||||
#endif // HDR_PLUS_CLIENT_UTILS_H
|
Loading…
Add table
Add a link
Reference in a new issue