add: Overlayable & OverlayablePolicy chunk

This commit is contained in:
REAndroid 2022-12-29 08:56:44 -05:00
parent bb1fe20f93
commit 06136b11e9
5 changed files with 370 additions and 8 deletions

View File

@ -0,0 +1,84 @@
/*
* Copyright (C) 2022 github.com/REAndroid
*
* 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.
*/
package com.reandroid.lib.arsc.chunk;
import com.reandroid.lib.arsc.base.Block;
import com.reandroid.lib.arsc.header.HeaderBlock;
import com.reandroid.lib.arsc.io.BlockLoad;
import com.reandroid.lib.arsc.io.BlockReader;
import com.reandroid.lib.arsc.item.ByteArray;
import com.reandroid.lib.arsc.item.FixedLengthString;
import java.io.IOException;
/**
* Replica of struct "ResTable_overlayable_header" as on AOSP androidfw/ResourceTypes.h
* We didn't test this class with resource table, if someone found a resource/apk please
* create issue on https://github.com/REAndroid/ARSCLib
* */
public class Overlayable extends BaseChunk implements BlockLoad {
private final FixedLengthString name;
private final FixedLengthString actor;
/**
* @link body
* As on AOSP there is only a description of header struct but no mention about
* chunk-content/body, thus we will use empty body byte array to avoid parse error
* */
private final ByteArray body;
public Overlayable() {
super(ChunkType.OVERLAYABLE, 1);
this.name = new FixedLengthString(512);
this.actor = new FixedLengthString(512);
this.body = new ByteArray();
addToHeader(this.name);
addToHeader(this.actor);
addChild(this.body);
this.actor.setBlockLoad(this);
}
public ByteArray getBody() {
return body;
}
public String getName(){
return this.name.get();
}
public void setName(String str){
this.name.set(str);
}
public String getActor(){
return this.actor.get();
}
public void setActor(String str){
this.actor.set(str);
}
@Override
public void onBlockLoaded(BlockReader reader, Block sender) throws IOException {
if(sender==this.actor){
HeaderBlock header = getHeaderBlock();
int bodySize=header.getChunkSize()-header.getHeaderSize();
this.body.setSize(bodySize);
}
}
@Override
protected void onChunkRefreshed() {
}
@Override
public String toString(){
return getClass().getSimpleName()+
": name='"+getName()
+"', actor='"+getActor()
+"', body-size="+getBody().size();
}
}

View File

@ -0,0 +1,242 @@
/*
* Copyright (C) 2022 github.com/REAndroid
*
* 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.
*/
package com.reandroid.lib.arsc.chunk;
import com.reandroid.lib.arsc.base.Block;
import com.reandroid.lib.arsc.io.BlockLoad;
import com.reandroid.lib.arsc.io.BlockReader;
import com.reandroid.lib.arsc.item.IntegerArray;
import com.reandroid.lib.arsc.item.IntegerItem;
import java.io.IOException;
import java.util.Collection;
/**
* Replica of struct "ResTable_overlayable_policy_header" as on AOSP androidfw/ResourceTypes.h
* We didn't test this class with resource table, if someone found a resource/apk please
* create issue on https://github.com/REAndroid/ARSCLib
* */
public class OverlayablePolicy extends BaseChunk implements BlockLoad {
private final IntegerItem flags;
private final IntegerItem entryCount;
private final IntegerArray tableRefArray;
public OverlayablePolicy(){
super(ChunkType.OVERLAYABLE_POLICY, 1);
this.flags = new IntegerItem();
this.entryCount = new IntegerItem();
this.tableRefArray = new IntegerArray();
addToHeader(this.flags);
addToHeader(this.entryCount);
addChild(this.tableRefArray);
this.entryCount.setBlockLoad(this);
}
@Override
public boolean isNull() {
return getTableReferenceCount()==0;
}
public int getTableReferenceCount(){
return getTableRefArray().size();
}
public Collection<Integer> listTableReferences(){
return getTableRefArray().toList();
}
public IntegerArray getTableRefArray() {
return tableRefArray;
}
public int getFlags() {
return flags.get();
}
public void setFlags(int flags){
this.flags.set(flags);
}
public void setFlags(PolicyFlag[] policyFlags){
setFlags(PolicyFlag.sum(policyFlags));
}
public void addFlag(PolicyFlag policyFlag){
int i = policyFlag==null? 0 : policyFlag.getFlagValue();
setFlags(getFlags() | i);
}
public PolicyFlag[] getPolicyFlags(){
return PolicyFlag.valuesOf(getFlags());
}
@Override
protected void onChunkRefreshed() {
this.entryCount.set(getTableRefArray().size());
}
@Override
public void onBlockLoaded(BlockReader reader, Block sender) throws IOException {
if(sender==this.entryCount){
this.tableRefArray.setSize(entryCount.get());
}
}
@Override
public String toString(){
return getClass().getSimpleName()+
": flags="+ PolicyFlag.toString(getPolicyFlags())
+"', count="+getTableReferenceCount();
}
public enum PolicyFlag {
PUBLIC(0x00000001),
SYSTEM_PARTITION(0x00000002),
VENDOR_PARTITION(0x00000004),
PRODUCT_PARTITION(0x00000008),
SIGNATURE(0x00000010),
ODM_PARTITION(0x00000020),
OEM_PARTITION(0x00000040),
ACTOR_SIGNATURE(0x00000080),
CONFIG_SIGNATURE(0x00000100);
private final int flag;
PolicyFlag(int flag) {
this.flag=flag;
}
public int getFlagValue(){
return this.flag;
}
public boolean contains(int flagsValue){
return (this.flag & flagsValue)==this.flag;
}
public static PolicyFlag[] valuesOf(int flagValue){
if(flagValue==0){
return null;
}
PolicyFlag[] values = values();
PolicyFlag[] tmp = new PolicyFlag[values.length];
int count=0;
for(int i=0;i<values.length;i++){
PolicyFlag flags = values[i];
if((flags.getFlagValue() & flagValue)==flags.getFlagValue()){
tmp[i]=flags;
count++;
}
}
if(count==0){
return null;
}
if(count==tmp.length){
return tmp;
}
PolicyFlag[] results=new PolicyFlag[count];
int j=0;
for(int i=0;i<tmp.length;i++){
if(tmp[i]!=null){
results[j]=tmp[i];
j++;
}
}
return results;
}
public static int sum(PolicyFlag[] flagsList){
if(flagsList==null||flagsList.length==0){
return 0;
}
int results = 0;
for(PolicyFlag flags:flagsList){
if(flags!=null){
results |=flags.getFlagValue();
}
}
return results;
}
public static boolean contains(PolicyFlag[] flagsList, PolicyFlag policyFlag){
if(flagsList==null||flagsList.length==0){
return policyFlag ==null;
}
if(policyFlag ==null){
return false;
}
for(PolicyFlag flags:flagsList){
if(policyFlag.equals(flags)){
return true;
}
}
return false;
}
public static String toString(PolicyFlag[] flagsList){
if(flagsList==null || flagsList.length==0){
return "NONE";
}
StringBuilder builder=new StringBuilder();
boolean appendOnce=false;
for(PolicyFlag flags:flagsList){
if(flags==null){
continue;
}
if(appendOnce){
builder.append('|');
}
builder.append(flags.name());
appendOnce=true;
}
if(appendOnce){
return builder.toString();
}
return "NONE";
}
public static PolicyFlag[] valuesOf(String flagsString){
if(flagsString==null){
return null;
}
flagsString=flagsString.trim().toUpperCase();
String[] namesList=flagsString.split("\\s*\\|\\s*");
PolicyFlag[] tmp = new PolicyFlag[namesList.length];
int count=0;
for(int i=0;i< namesList.length; i++){
PolicyFlag flags=nameOf(namesList[i]);
if(flags!=null){
tmp[i]=flags;
count++;
}
}
if(count==0){
return null;
}
if(count == tmp.length){
return tmp;
}
PolicyFlag[] results=new PolicyFlag[count];
int j=0;
for(int i=0;i<tmp.length;i++){
if(tmp[i]!=null){
results[j]=tmp[i];
j++;
}
}
return results;
}
public static PolicyFlag nameOf(String name){
if(name==null){
return null;
}
name=name.trim().toUpperCase();
for(PolicyFlag flags:values()){
if(name.equals(flags.name())){
return flags;
}
}
return null;
}
}
}

View File

@ -18,6 +18,7 @@ package com.reandroid.lib.arsc.chunk;
import com.reandroid.lib.arsc.array.LibraryInfoArray;
import com.reandroid.lib.arsc.array.SpecTypePairArray;
import com.reandroid.lib.arsc.base.Block;
import com.reandroid.lib.arsc.container.BlockList;
import com.reandroid.lib.arsc.container.PackageLastBlocks;
import com.reandroid.lib.arsc.container.SingleBlockContainer;
import com.reandroid.lib.arsc.container.SpecTypePair;
@ -57,6 +58,8 @@ package com.reandroid.lib.arsc.chunk;
private final SpecTypePairArray mSpecTypePairArray;
private final LibraryBlock mLibraryBlock;
private final StagedAlias mStagedAlias;
private final BlockList<Overlayable> mOverlayableList;
private final BlockList<OverlayablePolicy> mOverlayablePolicyList;
private final PackageLastBlocks mPackageLastBlocks;
@ -83,10 +86,14 @@ package com.reandroid.lib.arsc.chunk;
this.mSpecTypePairArray=new SpecTypePairArray();
this.mLibraryBlock=new LibraryBlock();
this.mStagedAlias=new StagedAlias();
this.mOverlayableList=new BlockList<>();
this.mOverlayablePolicyList=new BlockList<>();
this.mPackageLastBlocks = new PackageLastBlocks(
mSpecTypePairArray,
mLibraryBlock,
mStagedAlias);
mStagedAlias,
mOverlayableList,
mOverlayablePolicyList);
this.mEntriesGroup=new HashMap<>();
@ -106,6 +113,15 @@ package com.reandroid.lib.arsc.chunk;
addChild(mPackageLastBlocks);
}
public StagedAlias getStagedAlias(){
return mStagedAlias;
}
public BlockList<Overlayable> getOverlayableList(){
return mOverlayableList;
}
public BlockList<OverlayablePolicy> getOverlayablePolicyList(){
return mOverlayablePolicyList;
}
public void sortTypes(){
getSpecTypePairArray().sort();
}

View File

@ -15,10 +15,8 @@
*/
package com.reandroid.lib.arsc.container;
import com.reandroid.lib.arsc.chunk.ChunkType;
import com.reandroid.lib.arsc.chunk.*;
import com.reandroid.lib.arsc.array.SpecTypePairArray;
import com.reandroid.lib.arsc.chunk.LibraryBlock;
import com.reandroid.lib.arsc.chunk.StagedAlias;
import com.reandroid.lib.arsc.header.HeaderBlock;
import com.reandroid.lib.arsc.io.BlockReader;
@ -29,16 +27,24 @@ public class PackageLastBlocks extends FixedBlockContainer {
private final SpecTypePairArray mSpecTypePairArray;
private final LibraryBlock mLibraryBlock;
private final StagedAlias mStagedAlias;
private final BlockList<Overlayable> mOverlayableList;
private final BlockList<OverlayablePolicy> mOverlayablePolicyList;
public PackageLastBlocks(SpecTypePairArray specTypePairArray,
LibraryBlock libraryBlock,
StagedAlias stagedAlias){
super(3);
StagedAlias stagedAlias,
BlockList<Overlayable> overlayableList,
BlockList<OverlayablePolicy> overlayablePolicyList){
super(5);
this.mSpecTypePairArray=specTypePairArray;
this.mLibraryBlock=libraryBlock;
this.mStagedAlias=stagedAlias;
this.mOverlayableList=overlayableList;
this.mOverlayablePolicyList=overlayablePolicyList;
addChild(0, mSpecTypePairArray);
addChild(1, mLibraryBlock);
addChild(2, mStagedAlias);
addChild(3, mOverlayableList);
addChild(4, mOverlayablePolicyList);
}
@Override
@ -59,6 +65,10 @@ public class PackageLastBlocks extends FixedBlockContainer {
readSpecBlock(reader);
}else if(chunkType==ChunkType.LIBRARY){
readLibraryBlock(reader);
}else if(chunkType==ChunkType.OVERLAYABLE){
readOverlayable(reader);
}else if(chunkType==ChunkType.OVERLAYABLE_POLICY){
readOverlayablePolicy(reader);
}else if(chunkType==ChunkType.STAGED_ALIAS){
readStagedAlias(reader);
}else {
@ -80,6 +90,16 @@ public class PackageLastBlocks extends FixedBlockContainer {
stagedAlias.readBytes(reader);
mStagedAlias.addStagedAliasEntries(stagedAlias);
}
private void readOverlayable(BlockReader reader) throws IOException{
Overlayable overlayable = new Overlayable();
overlayable.readBytes(reader);
mOverlayableList.add(overlayable);
}
private void readOverlayablePolicy(BlockReader reader) throws IOException{
OverlayablePolicy overlayablePolicy = new OverlayablePolicy();
overlayablePolicy.readBytes(reader);
mOverlayablePolicyList.add(overlayablePolicy);
}
private void readUnexpectedBlock(BlockReader reader, HeaderBlock headerBlock) throws IOException{
throw new IOException(reader.getActualPosition()+", Unexpected block: "+headerBlock.toString());
}

View File

@ -53,8 +53,8 @@ public class HeaderBlock extends ExpandableBlockContainer {
mType.set(type);
}
public short getHeaderSize(){
return mHeaderSize.get();
public int getHeaderSize(){
return (0xffff & mHeaderSize.get());
}
public void setHeaderSize(short headerSize){
mHeaderSize.set(headerSize);