| /* |
| * Copyright (C) 2014 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. |
| */ |
| |
| package com.android.jack.library.v0002; |
| |
| import com.google.common.collect.ImmutableSet; |
| |
| import com.android.jack.analysis.dependency.Dependency; |
| import com.android.jack.backend.dex.DexFileWriter; |
| import com.android.jack.backend.jayce.JayceFileImporter; |
| import com.android.jack.library.FileType; |
| import com.android.jack.library.FileTypeDoesNotExistException; |
| import com.android.jack.library.InputJackLibrary; |
| import com.android.jack.library.JackLibraryFactory; |
| import com.android.jack.library.LibraryFormatException; |
| import com.android.jack.library.LibraryIOException; |
| import com.android.jack.library.LibraryVersionException; |
| import com.android.jack.library.MissingLibraryPropertyException; |
| import com.android.jack.library.PrebuiltCompatibility; |
| import com.android.sched.util.codec.ParsingException; |
| import com.android.sched.util.config.Config; |
| import com.android.sched.util.config.ThreadConfig; |
| import com.android.sched.util.config.id.PropertyId; |
| import com.android.sched.util.file.CannotCreateFileException; |
| import com.android.sched.util.file.CannotDeleteFileException; |
| import com.android.sched.util.file.NoSuchFileException; |
| import com.android.sched.util.file.NotDirectoryException; |
| import com.android.sched.util.file.NotFileOrDirectoryException; |
| import com.android.sched.util.log.LoggerFactory; |
| import com.android.sched.vfs.GenericInputVFS; |
| import com.android.sched.vfs.InputVDir; |
| import com.android.sched.vfs.InputVFS; |
| import com.android.sched.vfs.InputVFile; |
| import com.android.sched.vfs.MessageDigestFS; |
| import com.android.sched.vfs.PrefixedFS; |
| import com.android.sched.vfs.VFS; |
| import com.android.sched.vfs.VPath; |
| import com.android.sched.vfs.WrongVFSFormatException; |
| |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.EnumMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Properties; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| |
| import javax.annotation.CheckForNull; |
| import javax.annotation.Nonnegative; |
| import javax.annotation.Nonnull; |
| |
| /** |
| * Jack library used as input. |
| */ |
| public class InputJackLibraryImpl extends InputJackLibrary { |
| @Nonnull |
| private static final Logger logger = LoggerFactory.getLogger(); |
| |
| @Nonnull |
| private static final VPath RSC_PREFIX = new VPath("rsc", '/'); |
| |
| @Nonnull |
| private static final VPath LOG_PREFIX = new VPath("log", '/'); |
| |
| @Nonnull |
| private static final VPath META_PREFIX = new VPath("meta", '/'); |
| |
| @Nonnull |
| private static final VPath JAYCE_PREFIX = new VPath("jayce", '/'); |
| |
| @Nonnull |
| private static final VPath PREBUILT_PREFIX = new VPath("prebuilt", '/'); |
| |
| @Nonnull |
| private final Map<FileType, InputVFS> sectionVFS = |
| new EnumMap<FileType, InputVFS>(FileType.class); |
| |
| @Nonnull |
| private final VFS originalVFS; |
| |
| public InputJackLibraryImpl(@Nonnull VFS vfs, |
| @Nonnull Properties libraryProperties) throws LibraryVersionException, |
| LibraryFormatException { |
| super(libraryProperties, vfs); |
| originalVFS = vfs; |
| |
| check(); |
| fillFileTypes(); |
| } |
| |
| @Override |
| @Nonnull |
| public InputVFile getFile(@Nonnull FileType fileType, @Nonnull VPath typePath) |
| throws FileTypeDoesNotExistException { |
| try { |
| if (!containsFileType(fileType)) { |
| // Even if the file exists, it is not accessible because fileType does not belong to the |
| // library, thus do not return it. |
| throw new FileTypeDoesNotExistException(getLocation(), typePath, fileType); |
| } |
| InputVFS currentSectionVFS = getSectionVFS(fileType); |
| return currentSectionVFS.getRootInputVDir().getInputVFile( |
| buildFileVPath(fileType, typePath)); |
| } catch (NotFileOrDirectoryException e) { |
| throw new FileTypeDoesNotExistException(getLocation(), typePath, fileType); |
| } catch (NoSuchFileException e) { |
| throw new FileTypeDoesNotExistException(getLocation(), typePath, fileType); |
| } |
| } |
| |
| |
| @Override |
| @Nonnull |
| public InputVDir getDir(@Nonnull FileType fileType, @Nonnull VPath typePath) |
| throws FileTypeDoesNotExistException { |
| try { |
| InputVFS currentSectionVFS = getSectionVFS(fileType); |
| return currentSectionVFS.getRootInputVDir().getInputVDir(typePath); |
| } catch (NotDirectoryException e) { |
| throw new FileTypeDoesNotExistException(getLocation(), typePath, fileType); |
| } catch (NoSuchFileException e) { |
| throw new FileTypeDoesNotExistException(getLocation(), typePath, fileType); |
| } |
| } |
| |
| @Override |
| @Nonnull |
| public Iterator<InputVFile> iterator(@Nonnull FileType fileType) { |
| if (!containsFileType(fileType)) { |
| return ImmutableSet.<InputVFile>of().iterator(); |
| } |
| |
| List<InputVFile> inputVFiles = new ArrayList<InputVFile>(); |
| fillFiles(getSectionVFS(fileType).getRootInputVDir(), inputVFiles); |
| return inputVFiles.listIterator(); |
| } |
| |
| @Nonnull |
| private synchronized InputVFS getSectionVFS(@Nonnull FileType fileType) { |
| InputVFS currentSectionVFS; |
| if (sectionVFS.containsKey(fileType)) { |
| currentSectionVFS = sectionVFS.get(fileType); |
| } else { |
| VFS prefixedInputVFS = null; |
| try { |
| prefixedInputVFS = new PrefixedFS(vfs, getSectionPath(fileType)); |
| } catch (CannotCreateFileException e) { |
| // If library is well formed this exception can not be triggered |
| throw new AssertionError(e); |
| } catch (NotDirectoryException e) { |
| // If library is well formed this exception can not be triggered |
| throw new AssertionError(e); |
| } |
| if (fileType == FileType.PREBUILT) { |
| try { |
| currentSectionVFS = new GenericInputVFS(new MessageDigestFS(prefixedInputVFS, |
| ThreadConfig.get(JackLibraryFactory.MESSAGE_DIGEST_ALGO))); |
| } catch (WrongVFSFormatException e) { |
| // If library is well formed this exception can not be triggered |
| throw new AssertionError(e); |
| } |
| } else { |
| currentSectionVFS = new GenericInputVFS(prefixedInputVFS); |
| } |
| sectionVFS.put(fileType, currentSectionVFS); |
| } |
| return currentSectionVFS; |
| } |
| |
| @Override |
| public synchronized void close() throws LibraryIOException { |
| if (!originalVFS.isClosed()) { |
| try { |
| |
| for (InputVFS currentSectionVFS : sectionVFS.values()) { |
| currentSectionVFS.close(); |
| } |
| vfs.close(); |
| } catch (IOException e) { |
| throw new LibraryIOException(getLocation(), e); |
| } |
| } |
| } |
| |
| @Override |
| @Nonnegative |
| public int getMajorVersion() { |
| return Version.MAJOR; |
| } |
| |
| @Override |
| @Nonnegative |
| public int getSupportedMinorMin() { |
| return Version.MINOR_MIN; |
| } |
| |
| @Override |
| @Nonnegative |
| public int getSupportedMinor() { |
| return Version.MINOR; |
| } |
| |
| @Override |
| @Nonnull |
| public void delete(@Nonnull FileType fileType, @Nonnull VPath typePath) |
| throws CannotDeleteFileException, FileTypeDoesNotExistException { |
| try { |
| InputVFS currentSectionVFS = getSectionVFS(fileType); |
| currentSectionVFS.getRootInputVDir().getInputVFile(buildFileVPath(fileType, typePath)) |
| .delete(); |
| } catch (NotFileOrDirectoryException e) { |
| throw new FileTypeDoesNotExistException(getLocation(), typePath, fileType); |
| } catch (NoSuchFileException e) { |
| throw new FileTypeDoesNotExistException(getLocation(), typePath, fileType); |
| } |
| } |
| |
| @Override |
| @Nonnull |
| public String getPath() { |
| return vfs.getPath(); |
| } |
| |
| @Nonnull |
| public VPath buildFileVPath(@Nonnull FileType fileType, @Nonnull VPath vpath) { |
| VPath clonedPath = vpath.clone(); |
| clonedPath.addSuffix(getExtension(fileType)); |
| return clonedPath; |
| } |
| |
| @Override |
| @CheckForNull |
| public String getDigest() { |
| if (!containsFileType(FileType.PREBUILT)) { |
| return null; |
| } else { |
| return getSectionVFS(FileType.PREBUILT).getDigest(); |
| |
| } |
| } |
| |
| @Override |
| @Nonnull |
| protected String getPropertyPrefix(@Nonnull FileType type) { |
| return getPropertyPrefixImpl(type); |
| } |
| |
| @Nonnull |
| static String getPropertyPrefixImpl(@Nonnull FileType type) { |
| switch (type) { |
| case PREBUILT: |
| return "prebuilt"; |
| case JAYCE: |
| return "jayce"; |
| case META: |
| return "meta"; |
| case LOG: |
| return "log"; |
| case DEPENDENCIES: |
| return "meta"; |
| case RSC: |
| return "rsc"; |
| default: |
| throw new AssertionError(); |
| } |
| } |
| |
| @Nonnull |
| static String getExtension(@Nonnull FileType type) { |
| switch (type) { |
| case PREBUILT: |
| return DexFileWriter.DEX_FILE_EXTENSION; |
| case JAYCE: |
| return JayceFileImporter.JAYCE_FILE_EXTENSION; |
| case LOG: |
| return ".log"; |
| case DEPENDENCIES: |
| return Dependency.DEPENDENCY_FILE_EXTENSION; |
| default: |
| return ""; |
| } |
| } |
| |
| @Nonnull |
| static VPath getSectionPath(@Nonnull FileType type) { |
| switch (type) { |
| case PREBUILT: |
| return PREBUILT_PREFIX; |
| case JAYCE: |
| return JAYCE_PREFIX; |
| case META: |
| return META_PREFIX; |
| case LOG: |
| return LOG_PREFIX; |
| case DEPENDENCIES: |
| return META_PREFIX; |
| case RSC: |
| return RSC_PREFIX; |
| default: |
| throw new AssertionError(); |
| } |
| } |
| |
| @Override |
| public boolean hasCompliantPrebuilts() { |
| Config config = ThreadConfig.getConfig(); |
| |
| for (PropertyId<?> property : config.getPropertyIds()) { |
| if (property.hasCategory(PrebuiltCompatibility.class)) { |
| try { |
| String value = getProperty("config." + property.getName()); |
| PrebuiltCompatibility compatibility = property.getCategory(PrebuiltCompatibility.class); |
| if (compatibility != null) { |
| if (!compatibility.isCompatible(config, value)) { |
| return false; |
| } |
| } else { |
| if (!config.parseAs(value, property).equals(config.get(property))) { |
| return false; |
| } |
| } |
| } catch (MissingLibraryPropertyException e) { |
| logger.log(Level.FINE, e.getMessage()); |
| return false; |
| } catch (ParsingException e) { |
| logger.log(Level.FINE, "Property ''{0}'' is malformed from library {1}: {2}", |
| new Object[] {property.getName(), getLocation().getDescription(), e.getMessage()}); |
| return false; |
| } |
| } |
| } |
| |
| return true; |
| } |
| } |